Skip to content

feat(effort): per-task effort via effort:<level> labels, default high - #7

Merged
matthewtsmith merged 1 commit into
mainfrom
feat/effort
Oct 27, 2026
Merged

matthewtsmith merged 1 commit into
mainfrom
feat/effort

Conversation

@matthewtsmith

Copy link
Copy Markdown
Member

What

Lets the owner change the effort for one task from the CLI or the page, using Claude Code's own effort levels: low, medium, high, xhigh, max.

  • Every claude -p now gets --effort high, unless the issue has an effort:<level> label. Effort is pinned the same way --model is, so the interactive CLI's setting never leaks in.
  • There is deliberately no global override and no foreman.json key. Any level other than high is chosen for one task.
  • The label covers every role on the issue: builder, reviewer, validator and fix rounds. It is read on each dispatch, so a running session keeps its effort.

Surfaces

  • Labels: foreman init creates effort:low, effort:medium, effort:xhigh and effort:max. There is no effort:high, because no label already means high. Repos that already ran init need to run it once more.
  • CLI: foreman effort [<level>|default] [--issue <n>].
    • With no arguments it prints the default and every task that has an effort label.
    • With --issue and a level, it sets that task's effort. With a daemon running, the change goes through the daemon's page, so the board updates at once. With no daemon, it edits the label on GitHub directly.
    • A level without --issue is refused.
  • Page: each task on the Phases card gets a row of effort buttons, and pipeline rows get an effort tag. The buttons call POST /api/task-effort, which accepts only tasks listed on the board, like /api/task-model.
  • State: adds StatusReport.effort ({ default, levels }), PipelineRow.effort and PhaseTask.effort. Rows in an existing state.json read as null.

Tests

pnpm lint, pnpm typecheck and pnpm test (625) pass, and so does pnpm build. New tests cover:

  • the argv the dispatcher builds
  • choosing the effort from the label
  • label parsing (a level outside the five is ignored)
  • the label swap and the board update (choosing high or default removes the label)
  • the web route's allowlist
  • every ctl effort path
  • the labels init creates
  • reading an old state.json

🤖 Generated with Claude Code

https://claude.ai/code/session_01JrFSqoV3wDqhYLGUFs7ptP

Every claude -p now runs with --effort high unless the issue carries an
effort:<level> label (Claude Code's levels: low, medium, high, xhigh, max).
There is deliberately no global override or foreman.json knob: any other
level is chosen for one task.

- dispatch pins --effort; loop reads the label per dispatch (effortFor)
- init creates effort:low/medium/xhigh/max (no label means high)
- foreman effort [<level>|default] --issue <n>: through the running
  daemon's page, or straight to GitHub when none is running
- page: per-task effort buttons on the Phases card, effort tag on
  pipeline rows; POST /api/task-effort, allowlisted like /api/task-model
- StatusReport.effort, PipelineRow.effort, PhaseTask.effort (older
  state.json rows default to null)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrFSqoV3wDqhYLGUFs7ptP
@matthewtsmith
matthewtsmith merged commit 73fb3d2 into main Oct 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant