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/WORKFLOW.md b/WORKFLOW.md index 96af0aeb0..d06de94fa 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 @@ -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 +Requires a Linear MCP server or injected `linear_graphql` tool. If neither is present, stop and ask the user to configure Linear. -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 +## 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 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/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) 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 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