From d04e7aefdf2cf1ca870338d2135ab0be1953a040 Mon Sep 17 00:00:00 2001 From: David Astor Date: Thu, 5 Mar 2026 13:23:33 -0500 Subject: [PATCH 1/5] Remove guardrails ack flag and de-OpenAI the README The verbose --i-understand-that-this-will-be-running-without-the-usual-guardrails CLI flag added unnecessary friction to starting Symphony. Remove it along with the banner and associated test. Also strip OpenAI-specific URLs and model references from the README, replacing them with generic placeholders. --- README.md | 10 +++--- lib/symphony_elixir/cli.ex | 50 ++--------------------------- test/symphony_elixir/cli_test.exs | 52 ++++--------------------------- 3 files changed, 13 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index ca66743e2..9ce0e1b74 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,7 @@ _In this [demo video](.github/media/symphony-demo.mp4), Symphony monitors a Line 1. Polls Linear for candidate work 2. Creates an isolated workspace per issue -3. Launches Codex in [App Server mode](https://developers.openai.com/codex/app-server/) inside the - workspace +3. Launches Codex in App Server mode inside the workspace 4. Sends a workflow prompt to Codex 5. Keeps Codex working on the issue until the work is done @@ -31,8 +30,7 @@ Symphony stops the active agent for that issue and cleans up matching workspaces ## How to use it -1. Make sure your codebase is set up to work well with agents: see - [Harness engineering](https://openai.com/index/harness-engineering/). +1. Make sure your codebase is set up to work well with agents. 2. Get a new personal token in Linear via Settings → Security & access → Personal API keys, and set it as the `LINEAR_API_KEY` environment variable. 3. Copy this directory's `WORKFLOW.md` to your repo. @@ -59,7 +57,7 @@ mise exec -- elixir --version ## Run ```bash -git clone https://github.com/openai/symphony +git clone cd symphony mise trust mise install @@ -144,7 +142,7 @@ hooks: after_create: | git clone --depth 1 "$SOURCE_REPO_URL" . codex: - command: "$CODEX_BIN app-server --model gpt-5.3-codex" + command: "$CODEX_BIN app-server --model " ``` - If `WORKFLOW.md` is missing or has invalid YAML, startup and scheduling are halted until fixed. diff --git a/lib/symphony_elixir/cli.ex b/lib/symphony_elixir/cli.ex index d5c7eb183..a2d4a30a9 100644 --- a/lib/symphony_elixir/cli.ex +++ b/lib/symphony_elixir/cli.ex @@ -5,8 +5,7 @@ defmodule SymphonyElixir.CLI do alias SymphonyElixir.LogFile - @acknowledgement_switch :i_understand_that_this_will_be_running_without_the_usual_guardrails - @switches [{@acknowledgement_switch, :boolean}, logs_root: :string, port: :integer] + @switches [logs_root: :string, port: :integer] @type ensure_started_result :: {:ok, [atom()]} | {:error, term()} @type deps :: %{ @@ -33,15 +32,13 @@ defmodule SymphonyElixir.CLI do def evaluate(args, deps \\ runtime_deps()) do case OptionParser.parse(args, strict: @switches) do {opts, [], []} -> - with :ok <- require_guardrails_acknowledgement(opts), - :ok <- maybe_set_logs_root(opts, deps), + with :ok <- maybe_set_logs_root(opts, deps), :ok <- maybe_set_server_port(opts, deps) do run(Path.expand("WORKFLOW.md"), deps) end {opts, [workflow_path], []} -> - with :ok <- require_guardrails_acknowledgement(opts), - :ok <- maybe_set_logs_root(opts, deps), + with :ok <- maybe_set_logs_root(opts, deps), :ok <- maybe_set_server_port(opts, deps) do run(workflow_path, deps) end @@ -102,47 +99,6 @@ defmodule SymphonyElixir.CLI do end end - defp require_guardrails_acknowledgement(opts) do - if Keyword.get(opts, @acknowledgement_switch, false) do - :ok - else - {:error, acknowledgement_banner()} - end - end - - @spec acknowledgement_banner() :: String.t() - defp acknowledgement_banner do - lines = [ - "This Symphony implementation is a low key engineering preview.", - "Codex will run without any guardrails.", - "SymphonyElixir is not a supported product and is presented as-is.", - "To proceed, start with `--i-understand-that-this-will-be-running-without-the-usual-guardrails` CLI argument" - ] - - width = Enum.max(Enum.map(lines, &String.length/1)) - border = String.duplicate("─", width + 2) - top = "╭" <> border <> "╮" - bottom = "╰" <> border <> "╯" - spacer = "│ " <> String.duplicate(" ", width) <> " │" - - content = - [ - top, - spacer - | Enum.map(lines, fn line -> - "│ " <> String.pad_trailing(line, width) <> " │" - end) - ] ++ [spacer, bottom] - - [ - IO.ANSI.red(), - IO.ANSI.bright(), - Enum.join(content, "\n"), - IO.ANSI.reset() - ] - |> IO.iodata_to_binary() - end - defp set_logs_root(logs_root) do Application.put_env(:symphony_elixir, :log_file, LogFile.default_log_file(logs_root)) :ok diff --git a/test/symphony_elixir/cli_test.exs b/test/symphony_elixir/cli_test.exs index 4e4214793..d40b97dbb 100644 --- a/test/symphony_elixir/cli_test.exs +++ b/test/symphony_elixir/cli_test.exs @@ -3,46 +3,6 @@ defmodule SymphonyElixir.CLITest do alias SymphonyElixir.CLI - @ack_flag "--i-understand-that-this-will-be-running-without-the-usual-guardrails" - - test "returns the guardrails acknowledgement banner when the flag is missing" do - parent = self() - - deps = %{ - file_regular?: fn _path -> - send(parent, :file_checked) - true - end, - set_workflow_file_path: fn _path -> - send(parent, :workflow_set) - :ok - end, - set_logs_root: fn _path -> - send(parent, :logs_root_set) - :ok - end, - set_server_port_override: fn _port -> - send(parent, :port_set) - :ok - end, - ensure_all_started: fn -> - send(parent, :started) - {:ok, [:symphony_elixir]} - end - } - - assert {:error, banner} = CLI.evaluate(["WORKFLOW.md"], deps) - assert banner =~ "This Symphony implementation is a low key engineering preview." - assert banner =~ "Codex will run without any guardrails." - assert banner =~ "SymphonyElixir is not a supported product and is presented as-is." - assert banner =~ @ack_flag - refute_received :file_checked - refute_received :workflow_set - refute_received :logs_root_set - refute_received :port_set - refute_received :started - end - test "defaults to WORKFLOW.md when workflow path is missing" do deps = %{ file_regular?: fn path -> Path.basename(path) == "WORKFLOW.md" end, @@ -52,7 +12,7 @@ defmodule SymphonyElixir.CLITest do ensure_all_started: fn -> {:ok, [:symphony_elixir]} end } - assert :ok = CLI.evaluate([@ack_flag], deps) + assert :ok = CLI.evaluate([], deps) end test "uses an explicit workflow path override when provided" do @@ -74,7 +34,7 @@ defmodule SymphonyElixir.CLITest do ensure_all_started: fn -> {:ok, [:symphony_elixir]} end } - assert :ok = CLI.evaluate([@ack_flag, workflow_path], deps) + assert :ok = CLI.evaluate([workflow_path], deps) assert_received {:workflow_checked, ^expanded_path} assert_received {:workflow_set, ^expanded_path} end @@ -93,7 +53,7 @@ defmodule SymphonyElixir.CLITest do ensure_all_started: fn -> {:ok, [:symphony_elixir]} end } - assert :ok = CLI.evaluate([@ack_flag, "--logs-root", "tmp/custom-logs", "WORKFLOW.md"], deps) + assert :ok = CLI.evaluate(["--logs-root", "tmp/custom-logs", "WORKFLOW.md"], deps) assert_received {:logs_root, expanded_path} assert expanded_path == Path.expand("tmp/custom-logs") end @@ -107,7 +67,7 @@ defmodule SymphonyElixir.CLITest do ensure_all_started: fn -> {:ok, [:symphony_elixir]} end } - assert {:error, message} = CLI.evaluate([@ack_flag, "WORKFLOW.md"], deps) + assert {:error, message} = CLI.evaluate(["WORKFLOW.md"], deps) assert message =~ "Workflow file not found:" end @@ -120,7 +80,7 @@ defmodule SymphonyElixir.CLITest do ensure_all_started: fn -> {:error, :boom} end } - assert {:error, message} = CLI.evaluate([@ack_flag, "WORKFLOW.md"], deps) + assert {:error, message} = CLI.evaluate(["WORKFLOW.md"], deps) assert message =~ "Failed to start Symphony with workflow" assert message =~ ":boom" end @@ -134,6 +94,6 @@ defmodule SymphonyElixir.CLITest do ensure_all_started: fn -> {:ok, [:symphony_elixir]} end } - assert :ok = CLI.evaluate([@ack_flag, "WORKFLOW.md"], deps) + assert :ok = CLI.evaluate(["WORKFLOW.md"], deps) end end From dd40b7430b538a40a1fa77b01ab003575ea899f1 Mon Sep 17 00:00:00 2001 From: David Astor Date: Thu, 5 Mar 2026 13:27:42 -0500 Subject: [PATCH 2/5] Fix formatting in orchestrator.ex dispatch_state_set --- lib/symphony_elixir/orchestrator.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/symphony_elixir/orchestrator.ex b/lib/symphony_elixir/orchestrator.ex index bb88fdd4e..072664e02 100644 --- a/lib/symphony_elixir/orchestrator.ex +++ b/lib/symphony_elixir/orchestrator.ex @@ -600,7 +600,9 @@ defmodule SymphonyElixir.Orchestrator do defp dispatch_state_set do case Config.linear_dispatch_states() do - [] -> active_state_set() + [] -> + active_state_set() + states when is_list(states) -> states |> Enum.map(&normalize_issue_state/1) From 69233d156d383c4ac7edb74b2c1f2ce51eb70976 Mon Sep 17 00:00:00 2001 From: David Astor Date: Thu, 5 Mar 2026 13:32:09 -0500 Subject: [PATCH 3/5] Update WORKFLOW.md clone URL and remove stale elixir/ paths The project lives at the repo root now, so the cd elixir prefixes in hooks are wrong. Also points the clone URL at toodimes/symphony. --- WORKFLOW.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WORKFLOW.md b/WORKFLOW.md index 96af0aeb0..d1be3ae56 100644 --- a/WORKFLOW.md +++ b/WORKFLOW.md @@ -13,12 +13,12 @@ workspace: root: ~/code/symphony-workspaces hooks: after_create: | - git clone --depth 1 https://github.com/openai/symphony . + git clone --depth 1 https://github.com/toodimes/symphony . if command -v mise >/dev/null 2>&1; then - cd elixir && mise trust && mise exec -- mix deps.get + mise trust && mise exec -- mix deps.get fi before_remove: | - cd elixir && mise exec -- mix workspace.before_remove + mise exec -- mix workspace.before_remove agent: max_concurrent_agents: 10 max_turns: 20 From 3cbcf692e6110a58de16c84f3cdcdbfbd5dc733b Mon Sep 17 00:00:00 2001 From: David Astor Date: Thu, 5 Mar 2026 13:38:15 -0500 Subject: [PATCH 4/5] Trim WORKFLOW.md agent prompt from ~290 to ~130 lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prompt had massive redundancy — the same rules were restated across Default posture, Status map, Step 0, Step 1, Step 2, Guardrails, and Completion bar sections. Merged overlapping sections, eliminated duplicate instructions, and condensed 23 execution sub-steps into 9. --- WORKFLOW.md | 261 ++++++++++------------------------------------------ 1 file changed, 50 insertions(+), 211 deletions(-) diff --git a/WORKFLOW.md b/WORKFLOW.md index d1be3ae56..d06de94fa 100644 --- a/WORKFLOW.md +++ b/WORKFLOW.md @@ -63,229 +63,68 @@ Instructions: Work only in the provided repository copy. Do not touch any other path. -## Prerequisite: Linear MCP or `linear_graphql` tool is available - -The agent should be able to talk to Linear, either via a configured Linear MCP server or injected `linear_graphql` tool. If none are present, stop and ask the user to configure Linear. - -## Default posture - -- Start by determining the ticket's current status, then follow the matching flow for that status. -- Start every task by opening the tracking workpad comment and bringing it up to date before doing new implementation work. -- Spend extra effort up front on planning and verification design before implementation. -- Reproduce first: always confirm the current behavior/issue signal before changing code so the fix target is explicit. -- Keep ticket metadata current (state, checklist, acceptance criteria, links). -- Treat a single persistent Linear comment as the source of truth for progress. -- Use that single workpad comment for all progress and handoff notes; do not post separate "done"/summary comments. -- Treat any ticket-authored `Validation`, `Test Plan`, or `Testing` section as non-negotiable acceptance input: mirror it in the workpad and execute it before considering the work complete. -- When meaningful out-of-scope improvements are discovered during execution, - file a separate Linear issue instead of expanding scope. The follow-up issue - must include a clear title, description, and acceptance criteria, be placed in - `Backlog`, be assigned to the same project as the current issue, link the - current issue as `related`, and use `blockedBy` when the follow-up depends on - the current issue. -- Move status only when the matching quality bar is met. -- Operate autonomously end-to-end unless blocked by missing requirements, secrets, or permissions. -- Use the blocked-access escape hatch only for true external blockers (missing required tools/auth) after exhausting documented fallbacks. - -## Related skills +Requires a Linear MCP server or injected `linear_graphql` tool. If neither is present, stop and ask the user to configure Linear. + +## Skills - `linear`: interact with Linear. -- `commit`: produce clean, logical commits during implementation. -- `push`: keep remote branch current and publish updates. -- `pull`: keep branch updated with latest `origin/main` before handoff. -- `land`: when ticket reaches `Merging`, explicitly open and follow `.codex/skills/land/SKILL.md`, which includes the `land` loop. +- `commit`: produce clean, logical commits. +- `push`: keep remote branch current. +- `pull`: sync with latest `origin/main`. +- `land`: when ticket reaches `Merging`, open and follow `.codex/skills/land/SKILL.md`. + +## Rules + +- Determine the ticket's current status first, then follow the matching flow. +- Use exactly one persistent `## Codex Workpad` comment per issue for all progress tracking (see template below). Do not post separate summary comments. +- Plan and verify before implementing. Reproduce the issue signal before changing code. +- Treat any ticket-authored `Validation`, `Test Plan`, or `Testing` section as mandatory acceptance input — mirror it in the workpad and complete it before handoff. +- Keep ticket metadata current (state, acceptance criteria, links). +- Out-of-scope improvements go in a separate Backlog issue (with title, description, acceptance criteria, same project, `related` link to current issue). +- Do not edit the issue body/description for planning or progress tracking. +- Temporary proof edits (local-only validation hacks) must be reverted before commit. +- If blocked by missing tools/auth, exhaust fallbacks first. GitHub access is not a valid blocker until all fallback strategies are documented in the workpad. For true blockers, move to `Human Review` with a brief in the workpad: what's missing, why it blocks, and the exact human action needed. +- If the branch PR is already closed/merged, create a fresh branch from `origin/main` and start over. ## Status map -- `Backlog` -> out of scope for this workflow; do not modify. -- `Todo` -> queued; immediately transition to `In Progress` before active work. - - Special case: if a PR is already attached, treat as feedback/rework loop (run full PR feedback sweep, address or explicitly push back, revalidate, return to `Human Review`). -- `In Progress` -> implementation actively underway. -- `Human Review` -> PR is attached and validated; waiting on human approval. -- `Merging` -> approved by human; execute the `land` skill flow (do not call `gh pr merge` directly). -- `Rework` -> reviewer requested changes; planning + implementation required. -- `Done` -> terminal state; no further action required. - -## Step 0: Determine current ticket state and route - -1. Fetch the issue by explicit ticket ID. -2. Read the current state. -3. Route to the matching flow: - - `Backlog` -> do not modify issue content/state; stop and wait for human to move it to `Todo`. - - `Todo` -> immediately move to `In Progress`, then ensure bootstrap workpad comment exists (create if missing), then start execution flow. - - If PR is already attached, start by reviewing all open PR comments and deciding required changes vs explicit pushback responses. - - `In Progress` -> continue execution flow from current scratchpad comment. - - `Human Review` -> wait and poll for decision/review updates. - - `Merging` -> on entry, open and follow `.codex/skills/land/SKILL.md`; do not call `gh pr merge` directly. - - `Rework` -> run rework flow. - - `Done` -> do nothing and shut down. -4. Check whether a PR already exists for the current branch and whether it is closed. - - If a branch PR exists and is `CLOSED` or `MERGED`, treat prior branch work as non-reusable for this run. - - Create a fresh branch from `origin/main` and restart execution flow as a new attempt. -5. For `Todo` tickets, do startup sequencing in this exact order: - - `update_issue(..., state: "In Progress")` - - find/create `## Codex Workpad` bootstrap comment - - only then begin analysis/planning/implementation work. -6. Add a short comment if state and issue content are inconsistent, then proceed with the safest flow. - -## Step 1: Start/continue execution (Todo or In Progress) - -1. Find or create a single persistent scratchpad comment for the issue: - - Search existing comments for a marker header: `## Codex Workpad`. - - Ignore resolved comments while searching; only active/unresolved comments are eligible to be reused as the live workpad. - - If found, reuse that comment; do not create a new workpad comment. - - If not found, create one workpad comment and use it for all updates. - - Persist the workpad comment ID and only write progress updates to that ID. -2. If arriving from `Todo`, do not delay on additional status transitions: the issue should already be `In Progress` before this step begins. -3. Immediately reconcile the workpad before new edits: - - Check off items that are already done. - - Expand/fix the plan so it is comprehensive for current scope. - - Ensure `Acceptance Criteria` and `Validation` are current and still make sense for the task. -4. Start work by writing/updating a hierarchical plan in the workpad comment. -5. Ensure the workpad includes a compact environment stamp at the top as a code fence line: - - Format: `:@` - - Example: `devbox-01:/home/dev-user/code/symphony-workspaces/MT-32@7bdde33bc` - - Do not include metadata already inferable from Linear issue fields (`issue ID`, `status`, `branch`, `PR link`). -6. Add explicit acceptance criteria and TODOs in checklist form in the same comment. - - If changes are user-facing, include a UI walkthrough acceptance criterion that describes the end-to-end user path to validate. - - If changes touch app files or app behavior, add explicit app-specific flow checks to `Acceptance Criteria` in the workpad (for example: launch path, changed interaction path, and expected result path). - - If the ticket description/comment context includes `Validation`, `Test Plan`, or `Testing` sections, copy those requirements into the workpad `Acceptance Criteria` and `Validation` sections as required checkboxes (no optional downgrade). -7. Run a principal-style self-review of the plan and refine it in the comment. -8. Before implementing, capture a concrete reproduction signal and record it in the workpad `Notes` section (command/output, screenshot, or deterministic UI behavior). -9. Run the `pull` skill to sync with latest `origin/main` before any code edits, then record the pull/sync result in the workpad `Notes`. - - Include a `pull skill evidence` note with: - - merge source(s), - - result (`clean` or `conflicts resolved`), - - resulting `HEAD` short SHA. -10. Compact context and proceed to execution. - -## PR feedback sweep protocol (required) - -When a ticket has an attached PR, run this protocol before moving to `Human Review`: - -1. Identify the PR number from issue links/attachments. -2. Gather feedback from all channels: - - Top-level PR comments (`gh pr view --comments`). - - Inline review comments (`gh api repos///pulls//comments`). - - Review summaries/states (`gh pr view --json reviews`). -3. Treat every actionable reviewer comment (human or bot), including inline review comments, as blocking until one of these is true: - - code/test/docs updated to address it, or - - explicit, justified pushback reply is posted on that thread. -4. Update the workpad plan/checklist to include each feedback item and its resolution status. -5. Re-run validation after feedback-driven changes and push updates. -6. Repeat this sweep until there are no outstanding actionable comments. - -## Blocked-access escape hatch (required behavior) - -Use this only when completion is blocked by missing required tools or missing auth/permissions that cannot be resolved in-session. - -- GitHub is **not** a valid blocker by default. Always try fallback strategies first (alternate remote/auth mode, then continue publish/review flow). -- Do not move to `Human Review` for GitHub access/auth until all fallback strategies have been attempted and documented in the workpad. -- If a non-GitHub required tool is missing, or required non-GitHub auth is unavailable, move the ticket to `Human Review` with a short blocker brief in the workpad that includes: - - what is missing, - - why it blocks required acceptance/validation, - - exact human action needed to unblock. -- Keep the brief concise and action-oriented; do not add extra top-level comments outside the workpad. - -## Step 2: Execution phase (Todo -> In Progress -> Human Review) - -1. Determine current repo state (`branch`, `git status`, `HEAD`) and verify the kickoff `pull` sync result is already recorded in the workpad before implementation continues. -2. If current issue state is `Todo`, move it to `In Progress`; otherwise leave the current state unchanged. -3. Load the existing workpad comment and treat it as the active execution checklist. - - Edit it liberally whenever reality changes (scope, risks, validation approach, discovered tasks). -4. Implement against the hierarchical TODOs and keep the comment current: - - Check off completed items. - - Add newly discovered items in the appropriate section. - - Keep parent/child structure intact as scope evolves. - - Update the workpad immediately after each meaningful milestone (for example: reproduction complete, code change landed, validation run, review feedback addressed). - - Never leave completed work unchecked in the plan. - - For tickets that started as `Todo` with an attached PR, run the full PR feedback sweep protocol immediately after kickoff and before new feature work. -5. Run validation/tests required for the scope. - - Mandatory gate: execute all ticket-provided `Validation`/`Test Plan`/ `Testing` requirements when present; treat unmet items as incomplete work. - - Prefer a targeted proof that directly demonstrates the behavior you changed. - - You may make temporary local proof edits to validate assumptions (for example: tweak a local build input for `make`, or hardcode a UI account / response path) when this increases confidence. - - Revert every temporary proof edit before commit/push. - - Document these temporary proof steps and outcomes in the workpad `Validation`/`Notes` sections so reviewers can follow the evidence. - - If app-touching, run `launch-app` validation and capture/upload media via `github-pr-media` before handoff. -6. Re-check all acceptance criteria and close any gaps. -7. Before every `git push` attempt, run the required validation for your scope and confirm it passes; if it fails, address issues and rerun until green, then commit and push changes. -8. Attach PR URL to the issue (prefer attachment; use the workpad comment only if attachment is unavailable). - - Ensure the GitHub PR has label `symphony` (add it if missing). -9. Merge latest `origin/main` into branch, resolve conflicts, and rerun checks. -10. Update the workpad comment with final checklist status and validation notes. - - Mark completed plan/acceptance/validation checklist items as checked. - - Add final handoff notes (commit + validation summary) in the same workpad comment. - - Do not include PR URL in the workpad comment; keep PR linkage on the issue via attachment/link fields. - - Add a short `### Confusions` section at the bottom when any part of task execution was unclear/confusing, with concise bullets. - - Do not post any additional completion summary comment. -11. Before moving to `Human Review`, poll PR feedback and checks: - - Read the PR `Manual QA Plan` comment (when present) and use it to sharpen UI/runtime test coverage for the current change. - - Run the full PR feedback sweep protocol. - - Confirm PR checks are passing (green) after the latest changes. - - Confirm every required ticket-provided validation/test-plan item is explicitly marked complete in the workpad. - - Repeat this check-address-verify loop until no outstanding comments remain and checks are fully passing. - - Re-open and refresh the workpad before state transition so `Plan`, `Acceptance Criteria`, and `Validation` exactly match completed work. -12. Only then move issue to `Human Review`. - - Exception: if blocked by missing required non-GitHub tools/auth per the blocked-access escape hatch, move to `Human Review` with the blocker brief and explicit unblock actions. -13. For `Todo` tickets that already had a PR attached at kickoff: - - Ensure all existing PR feedback was reviewed and resolved, including inline review comments (code changes or explicit, justified pushback response). - - Ensure branch was pushed with any required updates. - - Then move to `Human Review`. - -## Step 3: Human Review and merge handling - -1. When the issue is in `Human Review`, do not code or change ticket content. -2. Poll for updates as needed, including GitHub PR review comments from humans and bots. -3. If review feedback requires changes, move the issue to `Rework` and follow the rework flow. -4. If approved, human moves the issue to `Merging`. -5. When the issue is in `Merging`, open and follow `.codex/skills/land/SKILL.md`, then run the `land` skill in a loop until the PR is merged. Do not call `gh pr merge` directly. -6. After merge is complete, move the issue to `Done`. - -## Step 4: Rework handling - -1. Treat `Rework` as a full approach reset, not incremental patching. -2. Re-read the full issue body and all human comments; explicitly identify what will be done differently this attempt. -3. Close the existing PR tied to the issue. -4. Remove the existing `## Codex Workpad` comment from the issue. -5. Create a fresh branch from `origin/main`. -6. Start over from the normal kickoff flow: - - If current issue state is `Todo`, move it to `In Progress`; otherwise keep the current state. - - Create a new bootstrap `## Codex Workpad` comment. - - Build a fresh plan/checklist and execute end-to-end. +- `Backlog` -> do not modify; wait for human to move to `Todo`. +- `Todo` -> move to `In Progress`, then start execution flow. If a PR is already attached, run PR feedback sweep first. +- `In Progress` -> continue execution from the current workpad. +- `Human Review` -> do not code or change ticket content; poll for review updates. +- `Merging` -> run the `land` skill (do not call `gh pr merge` directly). +- `Rework` -> full reset: close existing PR, delete workpad comment, fresh branch from `origin/main`, start over. +- `Done` -> shut down. -## Completion bar before Human Review +## Execution flow -- Step 1/2 checklist is fully complete and accurately reflected in the single workpad comment. -- Acceptance criteria and required ticket-provided validation items are complete. -- Validation/tests are green for the latest commit. -- PR feedback sweep is complete and no actionable comments remain. -- PR checks are green, branch is pushed, and PR is linked on the issue. -- Required PR metadata is present (`symphony` label). -- If app-touching, runtime validation/media requirements from `App runtime validation (required)` are complete. +1. Find or create the `## Codex Workpad` comment. Reconcile it: check off completed items, update the plan for current scope. +2. Run `pull` to sync with `origin/main`. Record the result in the workpad Notes. +3. Write a hierarchical plan with acceptance criteria and validation steps in the workpad. Self-review and refine before implementing. +4. Implement against the plan. Keep the workpad current — check off items, add discovered work, update after each milestone. +5. Validate: run tests, execute all ticket-provided test plan items, prefer targeted proofs. Ensure validation passes before every push. +6. Create/update PR. Attach PR URL to the issue. Ensure the PR has the `symphony` label. +7. Run PR feedback sweep: gather all comments (top-level, inline, review summaries), treat each as blocking until addressed or explicitly pushed back on. Repeat until clean. +8. Merge latest `origin/main`, rerun checks, confirm everything is green. Refresh the workpad so it matches completed work. +9. Move to `Human Review`. -## Guardrails +## Human Review and merge -- If the branch PR is already closed/merged, do not reuse that branch or prior implementation state for continuation. -- For closed/merged branch PRs, create a new branch from `origin/main` and restart from reproduction/planning as if starting fresh. -- If issue state is `Backlog`, do not modify it; wait for human to move to `Todo`. -- Do not edit the issue body/description for planning or progress tracking. -- Use exactly one persistent workpad comment (`## Codex Workpad`) per issue. -- If comment editing is unavailable in-session, use the update script. Only report blocked if both MCP editing and script-based editing are unavailable. -- Temporary proof edits are allowed only for local verification and must be reverted before commit. -- If out-of-scope improvements are found, create a separate Backlog issue rather - than expanding current scope, and include a clear - title/description/acceptance criteria, same-project assignment, a `related` - link to the current issue, and `blockedBy` when the follow-up depends on the - current issue. -- Do not move to `Human Review` unless the `Completion bar before Human Review` is satisfied. -- In `Human Review`, do not make changes; wait and poll. -- If state is terminal (`Done`), do nothing and shut down. -- Keep issue text concise, specific, and reviewer-oriented. -- If blocked and no workpad exists yet, add one blocker comment describing blocker, impact, and next unblock action. +1. In `Human Review`, do not code or change ticket content. Poll for updates. +2. If review feedback requires changes, move to `Rework`. +3. When issue reaches `Merging`, run the `land` skill until merged, then move to `Done`. + +## Completion bar before Human Review + +- Workpad checklist fully complete and accurate. +- All acceptance criteria and ticket-provided validation items complete. +- Validation/tests green for latest commit. +- PR feedback sweep clean — no outstanding actionable comments. +- PR checks green, branch pushed, PR linked on issue with `symphony` label. ## Workpad template -Use this exact structure for the persistent workpad comment and keep it updated in place throughout execution: +Use this exact structure for the persistent workpad comment: ````md ## Codex Workpad From 26c4ce4d24069810466dca72cd95e81ae14e8455 Mon Sep 17 00:00:00 2001 From: David Astor Date: Thu, 5 Mar 2026 13:41:46 -0500 Subject: [PATCH 5/5] Update tests for WORKFLOW.md changes The in-repo WORKFLOW.md now uses team_key instead of project_slug, string-form active_states, updated clone URL and hook paths. --- test/symphony_elixir/core_test.exs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/symphony_elixir/core_test.exs b/test/symphony_elixir/core_test.exs index 2eeb947c3..8bb50fa4d 100644 --- a/test/symphony_elixir/core_test.exs +++ b/test/symphony_elixir/core_test.exs @@ -82,16 +82,16 @@ defmodule SymphonyElixir.CoreTest do tracker = Map.get(config, "tracker", %{}) assert is_map(tracker) assert Map.get(tracker, "kind") == "linear" - assert is_binary(Map.get(tracker, "project_slug")) - assert is_list(Map.get(tracker, "active_states")) - assert is_list(Map.get(tracker, "terminal_states")) + assert is_binary(Map.get(tracker, "team_key")) + assert Map.has_key?(tracker, "active_states") + assert Map.has_key?(tracker, "terminal_states") hooks = Map.get(config, "hooks", %{}) assert is_map(hooks) - assert Map.get(hooks, "after_create") =~ "git clone --depth 1 https://github.com/openai/symphony ." - assert Map.get(hooks, "after_create") =~ "cd elixir && mise trust" + assert Map.get(hooks, "after_create") =~ "git clone --depth 1 https://github.com/toodimes/symphony ." + assert Map.get(hooks, "after_create") =~ "mise trust" assert Map.get(hooks, "after_create") =~ "mise exec -- mix deps.get" - assert Map.get(hooks, "before_remove") =~ "cd elixir && mise exec -- mix workspace.before_remove" + assert Map.get(hooks, "before_remove") =~ "mise exec -- mix workspace.before_remove" assert String.trim(prompt) != "" assert is_binary(Config.workflow_prompt()) @@ -754,7 +754,7 @@ defmodule SymphonyElixir.CoreTest do assert prompt =~ "Only stop early for a true blocker" assert prompt =~ "Do not include \"next steps for user\"" assert prompt =~ "open and follow `.codex/skills/land/SKILL.md`" - assert prompt =~ "Do not call `gh pr merge` directly" + assert prompt =~ "do not call `gh pr merge` directly" assert prompt =~ "Continuation context:" assert prompt =~ "retry attempt #2" end