Project Config (.cuekit.yaml)
.cuekit.yaml gives a repository a stable identity and safe defaults for submit_task, the TUI, Task Teams, and Team Strategies. cuekit reads it from the nearest parent directory of the working cwd.
Initialize
cd /path/to/your/repo
cuekit initThis writes a safe .cuekit.yaml with prompt-safe adapter defaults and adds .cuekit/tasks/ to .gitignore.
Available flags:
cuekit init --dry-run # preview files without writing
cuekit init --force # overwrite existing .cuekit.yaml
cuekit init --no-gitignore # do not touch .gitignore
cuekit init --unsafe-bypass # generate `permissions: bypass` (trusted repos only)TIP
For a fuller commented starting point, copy .cuekit.example.yaml instead:
cp .cuekit.example.yaml .cuekit.yamlWARNING
--unsafe-bypass writes adapters.<agent>.permissions: bypass. Only use it in repositories where you trust every contributor with full shell access from the agent. Project-derived role/agent defaults will still force prompt-safe adapter options unless a caller explicitly sets adapter_options.
Discovery and project identity
cuekit searches upward from cwd for the nearest .cuekit.yaml. When found:
- Its directory is the config root.
project_uidis derived fromconfig_root + project.id— so copied repos with identical config still get distinct ids.- Without
.cuekit.yaml, cuekit falls back to the Git root, then tocwd.
project.id is a stable human-readable label, not an isolation key. The combination with config_root is the actual isolation key.
Minimal example
project:
id: cuekit
name: Cuekit
tui:
scope: project # or: path
submit:
role: worker
agent: claude-code
model: sonnet
timeout_ms: 1800000
priority: normal
teams:
roles:
coordinator: planner
worker: worker
reviewer: reviewer
wait:
timeout_ms: 300000
poll_interval_ms: 2000
cleanup: keep-team
adapters:
claude-code:
permissions: prompt # safe defaultSubmit defaults
submit.* fills omitted fields for submit_task. Precedence (high → low):
- Explicit request field
- Selected Agent Profile field (for
agent_kind/model) .cuekit.yamlsubmit.*default
role is resolved first; the chosen Agent Profile can still supply agent/model. To opt out of a configured project timeout for one task, pass timeout_ms: null at submit time.
Multiplexer
cuekit defaults to tmux. Opt into zellij ≥ 0.43 or herdr ≥ 0.5 by setting multiplexer.backend:
multiplexer:
backend: zellij # or "herdr", default is "tmux"
strict: false # true → hard-fail if the backend is missingPer-task multiplexer dispatch: a task spawned under one backend stays attachable through that backend even if .cuekit.yaml is later switched. The owning backend is recorded at spawn time.
Task Teams defaults
teams:
roles:
coordinator: planner
worker: worker
reviewer: reviewer
finisher: pr-finisher
wait:
timeout_ms: 300000
poll_interval_ms: 2000
cleanup: keep-teamteams.roles.<position>is applied to asubmit_team_tasksitem only when it has apositionand no explicitrole.teams.wait.*supplies defaults forwait({ kind: "team" })when the request omits them.teams.cleanup: delete-empty-teamis reserved — usekeep-teamtoday.
Team Strategies
Define project-local missions under strategies. cuekit renders the strategy into the coordinator's prompt; it does not execute a workflow.
strategies:
docs-polish:
description: "Light README/docs improvements"
intent: "Make minimal docs-only changes and verify meaning is preserved."
recommended_team:
coordinator: { position: coordinator, role: planner, agent: pi }
worker: { position: worker, role: worker, agent: pi }
reviewer: { position: reviewer, role: reviewer, agent: claude-code, model: sonnet }
guardrails:
- "Keep changes docs-only."
- "Do not commit/push/PR unless explicitly requested."
success_criteria:
- "Diff is limited to README/docs."
- "Meaning is preserved."
checks:
- "git diff --check"
- "bun run check"
autonomy:
allow_additional_workers: true
require_reviewer: trueFull field reference and design rationale → Team Strategies.
TUI scope
tui:
scope: project # default — show tasks/teams for this project_uid
# scope: path # ignore project identity; scope to current path/Git roottui.scope: all is intentionally rejected by the config schema. Use cuekit tui --all for an explicit one-off global view.
Adapter permissions
adapters:
claude-code:
permissions: prompt # safe default
opencode:
permissions: prompt
gemini:
permissions: prompt # only toggles -y; --skip-trust is always applied
antigravity:
permissions: prompt # bypass emits --dangerously-skip-permissions; sandbox via adapter_options.sandbox: true
codex:
permissions: prompt # bypass emits --dangerously-bypass-approvals-and-sandbox (covers shell + sandbox + MCP-tool prompts)Safety rules:
permissions: promptforces safe permissions unless the caller explicitly passesadapter_options.permissions: bypassis allowed but should be reserved for trusted repos.- Project-derived
submit.role/submit.agent/teams.roles.<position>selections always forceadapter_options.dangerously_skip_permissions = falsewhen the caller does not explicitly supplyadapter_options.
Hooks
Fire-and-forget shell commands on lifecycle events. Hooks never block the workflow and never affect task status.
hooks:
on_task_complete:
command: "osascript -e 'display notification \"Done: $CUEKIT_OBJECTIVE\" with title \"cuekit\"'"
timeout: 10
on_task_fail:
command: "osascript -e 'display notification \"Failed: $CUEKIT_OBJECTIVE\" with title \"cuekit\"'"
timeout: 10Supported events: on_task_start, on_task_complete, on_task_fail, on_task_cancel, on_task_timeout, on_task_block, on_team_start, on_team_complete.
Each event accepts a single hook definition or an array (run concurrently). Hook commands are executed via /bin/sh -c and receive metadata via environment variables:
| Variable | Description |
|---|---|
CUEKIT_EVENT | Event name |
CUEKIT_TASK_ID | Task id |
CUEKIT_STATUS | Terminal status |
CUEKIT_AGENT_KIND | Adapter (e.g. claude-code) |
CUEKIT_AGENT_MODEL | Model id |
CUEKIT_OBJECTIVE | Truncated to 500 chars |
CUEKIT_TEAM_ID | Team id (if applicable) |
CUEKIT_POSITION | Team position |
CUEKIT_STRATEGY | Team strategy name |
CUEKIT_SESSION_ID | Session id |
CUEKIT_PROJECT_ID | Project id from .cuekit.yaml (if set) |
CUEKIT_DURATION_MS | Duration in ms |
Slack webhook example
hooks:
on_task_complete:
command: 'curl -s -X POST -H "Content-Type: application/json" -d "{\"text\":\"Task $CUEKIT_TASK_ID completed\"}" https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
timeout: 10Schema notes
Top-level keys are strict — unknown keys are rejected. Key constraints:
project.id:[A-Za-z0-9._-]+tui.scope:project|pathsubmit.priority:low|normal|highsubmit.timeout_ms: positive integer (or omit;nullis for runtime calls only)teams.cleanup:keep-team(delete-empty-teamis reserved)adapters.<agent>.permissions:prompt|bypassstrategies.<name>.recommended_team.<slot>.position:coordinator|worker|reviewer|finisher|observer
Full schema list (kept in sync with the implementation): docs/guides/project-config.md.
Related
- Quickstart — uses
cuekit initin step 2. - Team Strategies — full strategy field reference.
- Agent Profiles —
roleresolution and authoring. - MCP Tools —
start_team_strategy,submit_task,list({kind:"strategies"}).