Files
plane-agentd/config/agentd.example.yaml
T
jj.wang 6dc7e72ac8 Webhook receiver: Plane deliveries trigger a tick (PAD-7)
agentd webhook-serve (agentd/webhook.py, stdlib): verifies X-Plane-Signature
(HMAC-SHA256 hex of the body, constant-time; 401 on missing/bad), routes by
data.project to a configured tenant (others 202), coalesces deliveries within
3 s into one tick, runs one more tick when deliveries arrive during a tick,
and retries every 15 s for up to 2 min while the lock is held (tick command
exit 75: flock -E 75 in the cron scripts, cli tick on Busy). Ticks run in a
systemd scope so restarting the receiver never kills one. Log:
<log_dir>/webhook.log; GET /healthz.

Config: webhook section (key names only, PLANE_WEBHOOK_SECRET scrubbed from
child envs like the Plane tokens), notify: {kind: none} as a no-op hook
called on every state move; the unused per-project webhook_secret_key is
gone (Plane webhooks are workspace-level). systemd unit for the LXC and
tools/plane-webhook.py to create/rotate the Plane webhook as the workspace
admin (secret straight into the Vault, never printed).
2026-10-21 13:24:04 +00:00

108 lines
5.3 KiB
YAML

# plane-agentd example configuration (design.md §5). Values that are secrets are *Vault key names* only;
# agentd reads the token from the environment variable of the same name, injected by
# agent-access.py exec --secret-env PLANE_WINDOW10_API_TOKEN=PLANE_WINDOW10_API_TOKEN ...
# Copy to config/agentd.local.yaml (git-ignored) or point AGENTD_CONFIG at your file.
plane: {base_url: https://plane.kappiee.com, workspace: kappiee}
vault: {client: ~/.local/share/server-access-client/agent-access.py, config: https://nas.tail9531b.ts.net:8443/identity/agent.json}
agentd:
state_dir: state # relative to the repo root; JSON state, logs, heartbeat, local run dirs
helpers_dir: tools/win10 # win10-ps.sh / win10-put.sh (Windows terminals only); relative = repo
interval: 120 # seconds between ticks in --loop mode
max_rounds_per_thread: 8 # rebuild the executor thread (with a handoff summary) after this many rounds
comment_max_chars: 6000
cli_terminal: oregon # identity used by `agentd new/comment/state/assign`
# Plane webhook receiver (`agentd webhook-serve`, docs/runbook.md "Webhook"); leave the section out to run on cron only.
webhook:
bind: 127.0.0.1
port: 8790
path: /plane
secret_key: PLANE_WEBHOOK_SECRET # Vault key name of the Plane webhook secret (workspace-level webhook)
tick_command: [cron/agentd-tick.sh] # exits 75 when another tick holds the lock (flock -E 75)
debounce_seconds: 3
retry_seconds: 15
retry_window_seconds: 120
notify: {kind: none} # notification hook: only `none` (no-op) exists today
terminals:
win10:
transport: warpgate-ssh
target: win10
os: windows
launch: schtasks
repo: 'C:\Users\Administrator\Documents\GwentAssistantProject\gwent'
run_root: 'C:\Users\Administrator\Documents\GwentAssistantProject\gwent\runtime\agentd'
bins: {codex: 'C:\Users\Administrator\AppData\Local\Programs\OpenAI\Codex\bin\codex.exe'}
plane_user: window10
token_key: PLANE_WINDOW10_API_TOKEN
concurrency: 1
busy_processes: [codex] # do not start while a codex.exe we did not start is running
capabilities: [android, game]
executors: [codex]
oregon:
# remote even though agentd runs on oregon today: the dispatcher is moving to an LXC without agent CLIs
# (design §9), so this goes through Warpgate like any other host. `transport: local` + `launch: subprocess`
# still works for a dispatcher co-located with its executors.
transport: warpgate-ssh
target: oregon # agent-access.py target name
os: linux
launch: nohup
repo: /home/ubuntu/Documents/wjj/project/gwent
run_root: /home/ubuntu/.gwent-board/agentd-runs # absolute: the remote shell does not expand ~ inside quotes
plane_user: oregon
token_key: PLANE_OREGON_API_TOKEN
concurrency: 2
bins: {claude: /home/ubuntu/.local/bin/claude} # the SSH shell has the system PATH only
executors: [claude-code, codex, shell]
executors:
codex:
adapter: codex
run: "codex exec --json -C '{repo}' -s workspace-write -m {model} -c 'model_reasoning_effort=\"{effort}\"' {tier} -o '{out}' -"
resume: "codex exec resume {thread} --json -m {model} -c 'model_reasoning_effort=\"{effort}\"' {tier} -o '{out}' -"
tier_arg: "-c 'service_tier=\"{tier}\"'"
tier_defaults: {gpt-6.1-sol: fast} # tier when no label sets one (`tier:<x>`, `tier:none` = no tier)
thread_from: events.jsonl:thread.started.thread_id
last_message: '{out}'
models: [gpt-6.1-sol, gpt-6-astra]
default_effort: medium
claude-code:
adapter: claude-code
run: "claude -p --model {model} --output-format json --permission-mode {perm}"
resume: "claude -p --resume {thread} --model {model} --output-format json --permission-mode {perm}"
permission_mode: acceptEdits
thread_from: json:session_id
last_message: json:result
models: [sonnet, opus, haiku]
shell:
adapter: shell
run: '{script}'
resume: false
projects:
GWENT:
id: 79cb5a60-aa4f-4138-9864-1dd70426e665
key_prefix: GW
states: {backlog: Backlog, todo: Todo, running: In Progress, waiting: Waiting, review: Review, done: Done}
reviewer: oregon # Plane user that gets [review] items
answerer: oregon # Plane user that gets [question]/[blocked] and failures (default: reviewer)
protocol_file: /home/ubuntu/Documents/wjj/project/gwent/design/board-protocol.md
routing:
by_assignee: {window10: win10, oregon: oregon}
by_label:
'model:astra': {model: gpt-6-astra, effort: high}
'model:sol': {model: gpt-6.1-sol, tier: fast}
'model:opus': {model: opus}
'exec:claude': {executor: claude-code}
'needs-game': {serialize_group: game}
default_executor: {win10: codex, oregon: claude-code}
retry:
transient_max: 3
backoff_minutes: [2, 5, 10]
# transient_patterns / env_patterns default to the built-in lists in agentd/core.py
timeout_hours: 4
max_rounds_per_thread: 8
max_progress_rounds: 12 # after this many consecutive [progress] rounds: note + Waiting (answerer)
notify: {ntfy_topic: gwent, 'on': [waiting, review, failed]} # phase 3, not used yet; 'on' must be quoted (YAML 1.1 boolean)