From 5a600755158cf83d1083c23b3813b57f69ac0730 Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Sat, 4 Apr 2026 22:47:31 +0000 Subject: [PATCH] Teach lane-aware skills in agent dispatch (#143) Co-authored-by: Codex Agent Co-committed-by: Codex Agent --- bin/agent-dispatch.sh | 232 +++++++++++++++++++++++++++---------- playbooks/agent-lanes.json | 225 +++++++++++++++++++++++++++++++++++ 2 files changed, 399 insertions(+), 58 deletions(-) create mode 100644 playbooks/agent-lanes.json diff --git a/bin/agent-dispatch.sh b/bin/agent-dispatch.sh index 38e4a51b..deb16abe 100755 --- a/bin/agent-dispatch.sh +++ b/bin/agent-dispatch.sh @@ -1,11 +1,12 @@ #!/usr/bin/env bash -# agent-dispatch.sh — Generate a self-contained prompt for any agent +# agent-dispatch.sh — Generate a lane-aware prompt for any agent # # Usage: agent-dispatch.sh -# agent-dispatch.sh manus 42 Timmy_Foundation/the-nexus +# agent-dispatch.sh groq 42 Timmy_Foundation/the-nexus # # Outputs a prompt to stdout. Copy-paste into the agent's interface. -# The prompt includes everything: API URLs, token, git commands, PR creation. +# The prompt includes issue context, repo setup, lane coaching, and +# a short review checklist so dispatch itself teaches the right habits. set -euo pipefail @@ -13,86 +14,201 @@ AGENT_NAME="${1:?Usage: agent-dispatch.sh }" ISSUE_NUM="${2:?Usage: agent-dispatch.sh }" REPO="${3:?Usage: agent-dispatch.sh }" -GITEA_URL="http://143.198.27.163:3000" -TOKEN_FILE="$HOME/.hermes/${AGENT_NAME}_token" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LANES_FILE="${SCRIPT_DIR%/bin}/playbooks/agent-lanes.json" -if [ ! -f "$TOKEN_FILE" ]; then - echo "ERROR: No token found at $TOKEN_FILE" >&2 - echo "Create a Gitea user and token for '$AGENT_NAME' first." >&2 +resolve_gitea_url() { + if [ -n "${GITEA_URL:-}" ]; then + printf '%s\n' "${GITEA_URL%/}" + return 0 + fi + if [ -f "$HOME/.hermes/gitea_api" ]; then + python3 - "$HOME/.hermes/gitea_api" <<'PY' +from pathlib import Path +import sys + +raw = Path(sys.argv[1]).read_text().strip().rstrip("/") +print(raw[:-7] if raw.endswith("/api/v1") else raw) +PY + return 0 + fi + if [ -f "$HOME/.config/gitea/base-url" ]; then + tr -d '[:space:]' < "$HOME/.config/gitea/base-url" + return 0 + fi + echo "ERROR: set GITEA_URL or create ~/.hermes/gitea_api" >&2 + return 1 +} + +GITEA_URL="$(resolve_gitea_url)" + +resolve_token_file() { + local agent="$1" + local normalized + normalized="$(printf '%s' "$agent" | tr '[:upper:]' '[:lower:]')" + for candidate in \ + "$HOME/.hermes/${agent}_token" \ + "$HOME/.hermes/${normalized}_token" \ + "$HOME/.config/gitea/${agent}-token" \ + "$HOME/.config/gitea/${normalized}-token"; do + if [ -f "$candidate" ]; then + printf '%s\n' "$candidate" + return 0 + fi + done + for candidate in \ + "$HOME/.config/gitea/timmy-token" \ + "$HOME/.hermes/gitea_token_vps" \ + "$HOME/.hermes/gitea_token_timmy"; do + if [ -f "$candidate" ]; then + printf '%s\n' "$candidate" + return 0 + fi + done + return 1 +} + +TOKEN_FILE="$(resolve_token_file "$AGENT_NAME" || true)" +if [ -z "${TOKEN_FILE:-}" ]; then + echo "ERROR: No token found for '$AGENT_NAME'." >&2 + echo "Expected one of ~/.hermes/_token or ~/.config/gitea/-token" >&2 exit 1 fi -GITEA_TOKEN=$(cat "$TOKEN_FILE") -REPO_OWNER=$(echo "$REPO" | cut -d/ -f1) -REPO_NAME=$(echo "$REPO" | cut -d/ -f2) +GITEA_TOKEN="$(cat "$TOKEN_FILE")" +REPO_OWNER="${REPO%%/*}" +REPO_NAME="${REPO##*/}" BRANCH="${AGENT_NAME}/issue-${ISSUE_NUM}" -# Fetch issue title -ISSUE_TITLE=$(curl -sf -H "Authorization: token $GITEA_TOKEN" \ - "${GITEA_URL}/api/v1/repos/${REPO}/issues/${ISSUE_NUM}" 2>/dev/null | \ - python3 -c "import sys,json; print(json.loads(sys.stdin.read())['title'])" 2>/dev/null || echo "Issue #${ISSUE_NUM}") +python3 - "$LANES_FILE" "$AGENT_NAME" "$ISSUE_NUM" "$REPO" "$REPO_OWNER" "$REPO_NAME" "$BRANCH" "$GITEA_URL" "$GITEA_TOKEN" "$TOKEN_FILE" <<'PY' +import json +import sys +import textwrap +import urllib.error +import urllib.request -cat < 4000 else "") +recent_comments = comments[-3:] +comment_block = [] +for c in recent_comments: + author = c.get("user", {}).get("login", "unknown") + text = (c.get("body") or "").strip().replace("\r", "") + text = text[:600] + ("\n...[truncated]" if len(text) > 600 else "") + comment_block.append(f"- {author}: {text}") -git clone http://${AGENT_NAME}:${GITEA_TOKEN}@143.198.27.163:3000/${REPO_OWNER}/${REPO_NAME}.git /tmp/${AGENT_NAME}-work-${ISSUE_NUM} -cd /tmp/${AGENT_NAME}-work-${ISSUE_NUM} +comment_text = "\n".join(comment_block) if comment_block else "- (no comments yet)" -Check if branch exists (prior attempt): git ls-remote origin ${BRANCH} -If yes: git fetch origin ${BRANCH} && git checkout ${BRANCH} -If no: git checkout -b ${BRANCH} +skills = "\n".join(f"- {item}" for item in lane["skills_to_practice"]) +gaps = "\n".join(f"- {item}" for item in lane["missing_skills"]) +anti_lane = "\n".join(f"- {item}" for item in lane["anti_lane"]) +review = "\n".join(f"- {item}" for item in lane["review_checklist"]) -== STEP 3: UNDERSTAND THE PROJECT == +prompt = f"""You are {agent}, working on {repo_name} for Timmy Foundation. -Read README.md or any contributing guide. Check for tox.ini, Makefile, package.json. -Follow existing code conventions. +YOUR ISSUE: #{issue_num} — "{issue.get('title', f'Issue #{issue_num}')}" -== STEP 4: DO THE WORK == +REPO: {repo} +GITEA API: {gitea_url}/api/v1 +GITEA TOKEN FILE: {token_file} +WORK BRANCH: {branch} -Implement the fix/feature described in the issue. Run tests if the project has them. +LANE: +{lane['lane']} -== STEP 5: COMMIT AND PUSH == +SKILLS TO PRACTICE ON THIS ASSIGNMENT: +{skills} -git add -A -git commit -m "feat: (#${ISSUE_NUM}) +COMMON FAILURE MODE TO AVOID: +{gaps} -Fixes #${ISSUE_NUM}" -git push origin ${BRANCH} +ANTI-LANE: +{anti_lane} -== STEP 6: CREATE PR == +ISSUE BODY: +{body or "(empty issue body)"} -curl -s -X POST "${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/pulls" \\ - -H "Authorization: token ${GITEA_TOKEN}" \\ +RECENT COMMENTS: +{comment_text} + +WORKFLOW: +1. Read the issue body and recent comments carefully before touching code. +2. Clone the repo into /tmp/{agent}-work-{issue_num}. +3. Check whether {branch} already exists on origin; reuse it if it does. +4. Read the repo docs and follow its own tooling and conventions. +5. Do only the scoped work from the issue. If the task grows, stop and comment instead of freelancing expansion. +6. Run the repo's real verification commands. +7. Open a PR and summarize: + - what changed + - how you verified it + - any remaining risk or follow-up +8. Comment on the issue with the PR link and the same concise summary. + +GIT / API SETUP: +export GITEA_URL="{gitea_url}" +export GITEA_TOKEN_FILE="{token_file}" +export GITEA_TOKEN="$(tr -d '[:space:]' < "$GITEA_TOKEN_FILE")" +git config --global http."$GITEA_URL/".extraHeader "Authorization: token $GITEA_TOKEN" +git clone "$GITEA_URL/{repo}.git" /tmp/{agent}-work-{issue_num} +cd /tmp/{agent}-work-{issue_num} +git ls-remote --exit-code origin {branch} >/dev/null 2>&1 && git fetch origin {branch} && git checkout {branch} || git checkout -b {branch} + +ISSUE FETCH COMMANDS: +curl -s -H "Authorization: token $GITEA_TOKEN" "{gitea_url}/api/v1/repos/{repo}/issues/{issue_num}" +curl -s -H "Authorization: token $GITEA_TOKEN" "{gitea_url}/api/v1/repos/{repo}/issues/{issue_num}/comments" + +PR CREATION TEMPLATE: +curl -s -X POST "{gitea_url}/api/v1/repos/{repo}/pulls" \\ + -H "Authorization: token $GITEA_TOKEN" \\ -H "Content-Type: application/json" \\ - -d '{"title": "[${AGENT_NAME}] (#${ISSUE_NUM})", "body": "Fixes #${ISSUE_NUM}\n\n", "head": "${BRANCH}", "base": "main"}' + -d '{{"title":"[{agent}] (#{issue_num})","body":"Fixes #{issue_num}\\n\\n## Summary\\n- \\n\\n## Verification\\n- \\n\\n## Risks\\n- ","head":"{branch}","base":"main"}}' -== STEP 7: COMMENT ON ISSUE == - -curl -s -X POST "${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/${ISSUE_NUM}/comments" \\ - -H "Authorization: token ${GITEA_TOKEN}" \\ +ISSUE COMMENT TEMPLATE: +curl -s -X POST "{gitea_url}/api/v1/repos/{repo}/issues/{issue_num}/comments" \\ + -H "Authorization: token $GITEA_TOKEN" \\ -H "Content-Type: application/json" \\ - -d '{"body": "PR submitted. "}' + -d '{{"body":"PR submitted.\\n\\nSummary:\\n- \\n\\nVerification:\\n- \\n\\nRisks:\\n- "}}' -== RULES == -- Read project docs FIRST. -- Use the project's own test/lint tools. -- Respect git hooks. Do not skip them. -- If tests fail twice, STOP and comment on the issue. -- ALWAYS push your work. ALWAYS create a PR. No exceptions. -- Clean up: remove /tmp/${AGENT_NAME}-work-${ISSUE_NUM} when done. -PROMPT +REVIEW CHECKLIST BEFORE YOU PUSH: +{review} + +RULES: +- Do not skip hooks with --no-verify. +- Do not silently widen the scope. +- If verification fails twice or the issue is underspecified, stop and comment with what blocked you. +- Always create a PR instead of pushing to main. +- Clean up /tmp/{agent}-work-{issue_num} when done. +""" + +print(textwrap.dedent(prompt).strip()) +PY diff --git a/playbooks/agent-lanes.json b/playbooks/agent-lanes.json new file mode 100644 index 00000000..4d9ec4f5 --- /dev/null +++ b/playbooks/agent-lanes.json @@ -0,0 +1,225 @@ +{ + "Timmy": { + "lane": "sovereign review, architecture, release judgment, and governing decisions", + "skills_to_practice": [ + "final architectural judgment", + "release and rollback discipline", + "repo-boundary decisions", + "approval on sensitive control surfaces" + ], + "missing_skills": [ + "delegate routine backlog maintenance instead of carrying it personally" + ], + "anti_lane": [ + "routine backlog grooming", + "mechanical triage that Allegro can handle" + ], + "review_checklist": [ + "Does this preserve Timmy's sovereignty and repo boundaries?", + "Does this change require explicit local review before merge?", + "Is the proposed work smaller and more reversible than the previous state?" + ] + }, + "allegro": { + "lane": "tempo-and-dispatch, Gitea bridge, queue hygiene, and operational next-move selection", + "skills_to_practice": [ + "triage discipline", + "queue balancing", + "deduplicating issues and PRs", + "clear review handoffs to Timmy" + ], + "missing_skills": [ + "say no to work that should stay with Timmy or a builder" + ], + "anti_lane": [ + "owning final architecture", + "modifying product code without explicit approval" + ], + "review_checklist": [ + "Is this the best next move, not just a possible move?", + "Does this reduce duplicate work or operational drift?", + "Does Timmy need to judge this before execution continues?" + ] + }, + "perplexity": { + "lane": "research triage, integration evaluation, architecture memos, and open-source scouting", + "skills_to_practice": [ + "compressing research into decisions", + "comparing build-vs-borrow options", + "linking recommendations to issue #542 and current doctrine" + ], + "missing_skills": [ + "avoid generating duplicate backlog without a collapse pass" + ], + "anti_lane": [ + "shipping broad implementation without a bounded owner", + "opening speculative issue trees without consolidation" + ], + "review_checklist": [ + "Did I reduce uncertainty enough for a builder to act?", + "Did I consolidate duplicates instead of multiplying them?", + "Did I separate facts, options, and recommendation clearly?" + ] + }, + "ezra": { + "lane": "archival memory, RCA, onboarding, durable lessons, and operating history", + "skills_to_practice": [ + "extracting durable lessons from sessions", + "writing onboarding docs", + "failure analysis and postmortems", + "turning history into doctrine" + ], + "missing_skills": [ + "avoid acting like the primary shipper when the work needs a builder" + ], + "anti_lane": [ + "owning implementation-heavy tickets without backup", + "speculative architecture beyond the historical evidence" + ], + "review_checklist": [ + "What durable lesson should survive this work?", + "Did I link conclusions to evidence from issues, PRs, or runtime behavior?", + "Would a new wizard onboard faster because of this artifact?" + ] + }, + "KimiClaw": { + "lane": "long-context reading, extraction, and synthesis before implementation", + "skills_to_practice": [ + "digesting large issue threads", + "extracting action items from dense context", + "summarizing codebase slices for builders" + ], + "missing_skills": [ + "handoff crisp conclusions instead of staying in exploratory mode" + ], + "anti_lane": [ + "critical-path implementation without a bounded scope", + "becoming a second generic architecture persona" + ], + "review_checklist": [ + "Did I turn long context into a smaller decision surface?", + "Is my handoff specific enough for a builder to act immediately?", + "Did I avoid speculative side quests?" + ] + }, + "codex-agent": { + "lane": "workflow hardening, cleanup, migration verification, repo-boundary enforcement, and bounded implementation", + "skills_to_practice": [ + "closing migration drift", + "cutting dead code safely", + "packaging changes as reviewable PRs" + ], + "missing_skills": [ + "stay out of wide ideation unless explicitly asked" + ], + "anti_lane": [ + "unbounded speculative architecture", + "owning social authority instead of shipping truth" + ], + "review_checklist": [ + "Did I verify live truth, not just repo intent?", + "Is the change smaller, cleaner, and more reversible?", + "Did I leave a reviewable trail for Timmy and Allegro?" + ] + }, + "groq": { + "lane": "fast bounded implementation, tactical bug fixes, and narrow feature slices", + "skills_to_practice": [ + "keeping changes small", + "shipping with verification", + "staying within the acceptance criteria" + ], + "missing_skills": [ + "do not trade correctness for speed when the issue is ambiguous" + ], + "anti_lane": [ + "broad architectural design", + "open-ended exploratory research" + ], + "review_checklist": [ + "Is the task tightly scoped enough to finish cleanly?", + "Did I verify the fix, not just write it?", + "Did I avoid widening the blast radius?" + ] + }, + "manus": { + "lane": "moderate-scope support implementation and dependable follow-through on already-scoped work", + "skills_to_practice": [ + "finishing bounded tasks cleanly", + "good implementation hygiene", + "clear PR summaries" + ], + "missing_skills": [ + "escalate when the scope stops being moderate" + ], + "anti_lane": [ + "owning ambiguous architecture", + "soloing sprawling multi-repo initiatives" + ], + "review_checklist": [ + "Is this still moderate scope?", + "Did I prove the work and summarize it clearly?", + "Should a higher-context wizard review before more expansion?" + ] + }, + "claude": { + "lane": "hard refactors, deep implementation, and test-heavy multi-file changes after tight scoping", + "skills_to_practice": [ + "respecting scope constraints", + "deep code transformation with tests", + "explaining risks clearly in PRs" + ], + "missing_skills": [ + "do not let large capability turn into unsupervised backlog or code sprawl" + ], + "anti_lane": [ + "self-directed issue farming", + "taking broad architecture liberty without a clear charter" + ], + "review_checklist": [ + "Did I stay inside the scoped problem?", + "Did I leave tests or verification stronger than before?", + "Is there hidden blast radius that Timmy should see explicitly?" + ] + }, + "gemini": { + "lane": "frontier architecture, research-heavy prototypes, and long-range design thinking", + "skills_to_practice": [ + "turning speculation into decision frameworks", + "prototype design under doctrine constraints", + "making architecture legible to builders" + ], + "missing_skills": [ + "collapse duplicate ideation before it becomes backlog noise" + ], + "anti_lane": [ + "unsupervised backlog flood", + "acting like a general execution engine for every task" + ], + "review_checklist": [ + "Is this recommendation strategically important enough to keep?", + "Did I compress, not expand, the decision tree?", + "Did I hand off something a builder can actually execute?" + ] + }, + "grok": { + "lane": "adversarial review, edge cases, and provocative alternate angles", + "skills_to_practice": [ + "finding weird failure modes", + "challenging assumptions safely", + "stress-testing plans" + ], + "missing_skills": [ + "flag whether a provocative idea is a test, a recommendation, or a risk" + ], + "anti_lane": [ + "primary ownership of stable delivery", + "final architectural authority" + ], + "review_checklist": [ + "What assumption fails under pressure?", + "Is this edge case real enough to matter now?", + "Did I make the risk actionable instead of just surprising?" + ] + } +}