Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Operate the AWS-hosted Pilot daemon (founder box) — status, dashboard, logs, queue queries, start/stop/restart, rebuild/upgrade, metrics tunnel, troubleshooting. Auto-invoke when user says "pilot aws", "check the box", "aws daemon", "pilot on aws", "box status", "restart pilot on aws", "box logs", or any operation against the hosted daemon.
.claude/skills/qf-studio-pilot-aws/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 358% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 132% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 97% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 103% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 89% | 0% |
Since the S6-lite cutover (2026-07-16, TASK-409) the Pilot daemon runs on an EC2 box, NOT locally. Local pgrep pilot returning 0 is correct.
INSTANCE i-0e0c1ca34e7b561f9 # "pilot-founder-box", t3.xlarge, eu-central-1a
PROFILE quantflow # export AWS_PROFILE=quantflow for every aws call
REGION eu-central-1
RUNNER i-0147f5c24d234cdbb # mgmt runner (AdministratorAccess) — IAM/privileged ops only
DAEMON tmux session "pilot" as ec2-user, wrapper /home/ec2-user/start-pilot.sh
BINARY /var/lib/pilot/bin/pilot # ec2-user-owned (self-upgrade works, #4470); /usr/local/bin/pilot is a SYMLINK to it — never `sudo install` over the symlink; rollback at pilot.prev
STATE /home/ec2-user/.pilot → /var/lib/pilot/pilot-home (200GB data volume)
REPOS /Users/aleks.petrov/Projects → /var/lib/pilot/repos (path shim — ledger keys
on the macOS-era absolute paths; NEVER "fix" these symlinks)
DB /home/ec2-user/.pilot/data/pilot.db
LOG /home/ec2-user/.pilot/logs/daemon.log (+ daemon-stderr.log)bashexport AWS_PROFILE=quantflow AWS_DEFAULT_REGION=eu-central-1 CMD=$(aws ssm send-command --instance-ids i-0e0c1ca34e7b561f9 \ --document-name AWS-RunShellScript \ --parameters 'commands=["<shell here>"]' \ --query Command.CommandId --output text) sleep 10 aws ssm get-command-invocation --command-id $CMD \ --instance-id i-0e0c1ca34e7b561f9 --query StandardOutputContent --output text
For multi-line/quote-heavy payloads write a JSON file and use --parameters file:///tmp/x.json; for shipping FILES to the box, base64 the content into the command (echo <b64> | base64 -d > target) — inline heredocs with \n escapes DO NOT survive SSM JSON (verified failure mode).
bash~/bin/pilot-board # daemon health, queue, autopilot, log tail ~/bin/pilot-board --gh # + GitHub issues/PRs (costs shared user quota — sparingly)
Remote half lives at /usr/local/bin/pilot-board-remote on the box (edit there).
bash~/bin/pilot-dash # SSM interactive → tmux attach -t pilot
Detach: Ctrl-B then D. NEVER press q or Ctrl-C inside the TUI — that stops the daemon. Fallback: plain ssm session → sudo su - ec2-user → tmux attach -t pilot.
bash# tail (adjust -n / add grep): SSM: tail -50 /home/ec2-user/.pilot/logs/daemon.log # common filters: 'rate limit', 'claim lost', 'approval', 'ERROR', a task id
bashSSM: sqlite3 -column /home/ec2-user/.pilot/data/pilot.db \ "SELECT task_id,status,datetime(created_at) FROM executions \ WHERE status IN ('running','queued') ORDER BY created_at;"
Key tables: executions, execution_claims (task_id, project_path, generation), autopilot_pr_state, autopilot_scope_release, instance_events. ⚠️ Timestamp trap: pre-2026-07-16 rows may carry legacy …+02:00 string format — never filter by string time ranges across eras; use rowid or exact ids.
Never do these on your own judgment during watch/autonomous modes; in interactive sessions get explicit user go-ahead. In-flight executions die (they retry via generation claims — proven safe, but wasteful).
bash# STOP (graceful; wait, then verify 0): SSM: sudo -iu ec2-user tmux send-keys -t pilot C-c # TUI quit = graceful shutdown sleep 15; ps -eo comm | grep -c '^pilot$' # must be 0 # START: SSM: sudo -iu ec2-user tmux new-session -d -s pilot -x 220 -y 50 /home/ec2-user/start-pilot.sh sleep 20; ps -eo comm | grep -c '^pilot$' # must be 1; then check pilot-board # RESTART = STOP, verify, START, verify (banner version + no Telegram 409 + poller ticks).
After ANY start: verify version (/usr/local/bin/pilot version), exactly 1 process, curl -s localhost:9091/metrics | grep pilot_queue_depth (via SSM).
bashSSM (as ec2-user, NO sudo — dir is ec2-user-owned since 2026-07-19): cd /Users/aleks.petrov/Projects/startups/pilot && \ git fetch -q --tags origin main && git checkout -q <tag-or-origin/main> && \ make build && install -m 0755 bin/pilot /var/lib/pilot/bin/pilot && \ git checkout -q main && /var/lib/pilot/bin/pilot version
Then RESTART (above) to activate. Prefer building from a released tag. For releases, daemon self-upgrade also works now (#4470 preflight + writable dir) — letting it upgrade itself on the next train is the default path. Expect ~1 quiet hour post-restart until #4391 ships: startup rescans can burn the GitHub user-aggregate rate pool (see Troubleshooting).
bash~/bin/pilot-tunnel # box:9091 → localhost:9091, keep running; then `pilot-tui` (grafterm alias)
bashaws ssm start-session --target i-0e0c1ca34e7b561f9 --profile quantflow --region eu-central-1 sudo su - ec2-user
User aleks lacks iam:PassRole/ec2:CreateVolume etc. Route through the mgmt runner via SSM RunShellScript on i-0147f5c24d234cdbb (it has admin). Scope every grant minimally; never print policy docs containing secrets.
repos (dual-serve = cross-machine duplicate class; claims are per-DB). Rollback procedure lives in .agent/tasks/TASK-409-s6-lite-aws-cutover.md.
/Users/aleks.petrov/... symlinks on thebox) — ledger + claims key on those exact strings.
session, and the daemon. Prefer sqlite/metrics over gh for status. If the daemon logs "rate limit exceeded for user ID …" — it self-recovers on the rolling window; do not thrash retries. (#4391 tracks the durable fix.)
ps full args of processes holdingtokens; the wrapper script pattern exists precisely to keep tokens out of argv. Config on the box is verbatim-from-laptop; changes = operator consent + restart.
rendered as "rebase" until the GH-4383 fix is in the running binary).
source produced it: box DB (via SSM), GitHub, or the laptop archive. The laptop's ~/.pilot/data/pilot.db is a FROZEN pre-2026-07-16 archive (S6-lite cutover) — plausible-looking rows, months stale. A 2026-07-27 incident: a session read it and confidently misdiagnosed healthy tasks as "failed". Before reasoning about any DB: verify the path is the box's (/var/lib/pilot/pilot-home/data/pilot.db) and check row freshness (select max(datetime(created_at)) from executions). mem-160 family.
| Symptom | Likely cause | Move | |---|---|---| | Board says queue empty but daemon log shows executions; log claim generations exceed claims table | split-brain shadow ledger (#4393 class — daemon opened a DB at an unshimmed path) | sudo readlink /proc/$(pgrep -x pilot)/fd/* must include /var/lib/pilot/pilot-home/data/pilot.db; if not: STOP daemon, locate+merge shadow DB, fix shim | | ALL task executions fail unknown: exit status 1 after ~3m, 0 tokens, stream shows api_retry/fetch failed; judge/preflight children work | RLIMIT_AS cap on executor children (#4401 class — GH-3028 "RSS cap", darwin no-op) | grep 'address space' /proc/<claude-child>/limits must be unlimited; config subprocess_limits is enabled: false since 2026-07-17 (backup config.yaml.bak-4396) — OOM cap off until #4401 | | Queue frozen, pollers 403 "rate limit … user ID" | user-aggregate GitHub pool exhausted (startup rescans, parallel sessions) | wait for rolling window; stop nonessential gh usage; see #4391 | | Queue frozen, "dispatch claim lost" every poll, no 403s | dead-owner non-terminal rows holding gen-N claims (post-restart/cutover) | see #4392; workaround = mark orphan rows stalled with audit note (exact-id UPDATE, never string time-ranges) — this is a RECOVERY signal (retry the task), not a cancel; see next row if the goal is to stop a task | | Need to permanently stop a task from ever being re-picked (dup ticket, wrong scope, abandoned, operator error) | stalled is NOT a cancel verb — it means "dead owner, retry me" and the dispatcher grants it fresh generations exempt from the repick hard cap forever if hand-written for this purpose (GH-4655 incident) | pilot task cancel <task-id> [--project <path>] [--reason "..."] (GH-4678) — the real terminal cancel; NEVER hand-write status='stalled' to try to stop a task | | tmux session gone, no pilot process | wrapper/script error at spawn | check daemon-stderr.log; verify wrapper intact (cat start-pilot.sh); restart per above | | TUI monochrome | TERM captured at daemon start | ~/.tmux.conf already sets 256color; colors return on next restart — do not bounce for paint | | PR stuck "rebase N/3" in panel | awaiting_approval mislabel | ledger: SELECT stage FROM autopilot_pr_state WHERE pr_number=N | | Box unreachable via SSM | agent/instance down | aws ec2 describe-instances --instance-ids i-0e0c… → LOUD escalate to operator; never assume | | Multi-day uptime right after a train — looks like "installed but never restarted" | NOT a stale process — self-upgrade's restart leg is syscall.Exec (PID preserved, so ps etime/uptime survives the restart; mem hot-restart-preserves-pid-uptime-false-mismatch). Since 2026-08-13 board ver reads the RUNNING process (pilot_build_info metric, #4864/PR#4865; repointed pilot-board-remote) — a (disk!) suffix means the daemon metric was unreachable and the value is the disk binary's | Trust ver (metric-sourced). Cross-check: curl -s localhost:9091/metrics \| grep pilot_build_info via SSM, or grep 'upgrade verified complete' ~/.pilot/logs/daemon.log (boot-reconcile from=/to= logged by the NEW image; failure counterpart previous upgrade did NOT take effect). Do NOT bounce the daemon on uptime evidence alone |
.agent/tasks/TASK-409-s6-lite-aws-cutover.md.agent/sops/operations/safe-daemon-restart.md (verify PID+banner ALWAYS)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 9,262 | 13,205 | +43% | 1 | 1 | 0% | 1,524 | 4,331 | +184% | 0 | 0 | — |
case-02 | fail→pass | 27,792 | 14,253 | -49% | 1 | 1 | 0% | 1,345 | 6,165 | +358% | 0 | 0 | — |
case-03 | fail→pass | 17,299 | 16,399 | -5% | 1 | 1 | 0% | 2,812 | 6,521 | +132% | 0 | 0 | — |
case-04 | pass→pass | 8,613 | 6,590 | -23% | 1 | 1 | 0% | 1,815 | 4,599 | +153% | 0 | 0 | — |
case-05 | pass→pass | 14,255 | 28,372 | +99% | 1 | 1 | 0% | 2,859 | 9,441 | +230% | 0 | 0 | — |
case-11 | pass→pass | 13,389 | 8,997 | -33% | 1 | 1 | 0% | 2,187 | 4,780 | +119% | 0 | 0 | — |
case-06 | pass→pass | 6,872 | 6,570 | -4% | 1 | 1 | 0% | 1,449 | 4,567 | +215% | 0 | 0 | — |
case-07 | fail→pass | 12,035 | 4,806 | -60% | 1 | 1 | 0% | 2,143 | 4,223 | +97% | 0 | 0 | — |
case-08 | fail→pass | 11,661 | 4,561 | -61% | 1 | 1 | 0% | 1,984 | 4,023 | +103% | 0 | 0 | — |
case-09 | fail→pass | 15,051 | 7,503 | -50% | 1 | 1 | 0% | 2,327 | 4,395 | +89% | 0 | 0 | — |
case-10 | fail→pass | 5,079 | 5,532 | +9% | 1 | 1 | 0% | 877 | 4,314 | +392% | 0 | 0 | — |
case-12 | fail→pass | 10,307 | 7,643 | -26% | 1 | 1 | 0% | 1,803 | 4,737 | +163% | 0 | 0 | — |
case-13 | pass→pass | 12,031 | 3,720 | -69% | 1 | 1 | 0% | 2,086 | 3,966 | +90% | 0 | 0 | — |
case-14 | fail→pass | 7,686 | 3,214 | -58% | 1 | 1 | 0% | 1,193 | 3,757 | +215% | 0 | 0 | — |
case-15 | fail→pass | 14,904 | 6,534 | -56% | 1 | 1 | 0% | 2,150 | 4,474 | +108% | 0 | 0 | — |
case-16 | fail→fail | 14,275 | 7,254 | -49% | 1 | 1 | 0% | 2,388 | 4,497 | +88% | 0 | 0 | — |
case-17 | fail→fail | 12,457 | 7,445 | -40% | 1 | 1 | 0% | 1,880 | 4,469 | +138% | 0 | 0 | — |
case-18 | fail→pass | 9,794 | 6,820 | -30% | 1 | 1 | 0% | 1,579 | 4,588 | +191% | 0 | 0 | — |
case-19 | fail→pass | 7,664 | 3,408 | -56% | 1 | 1 | 0% | 1,320 | 3,919 | +197% | 0 | 0 | — |
case-20 | fail→pass | 10,978 | 4,202 | -62% | 1 | 1 | 0% | 1,937 | 4,035 | +108% | 0 | 0 | — |
case-21 | fail→pass | 9,907 | 1,748 | -82% | 1 | 1 | 0% | 1,785 | 3,531 | +98% | 0 | 0 | — |
case-22 | fail→pass | 12,421 | 2,250 | -82% | 1 | 1 | 0% | 1,945 | 3,596 | +85% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 20 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +64 percentage points is the difference between those two pass rates over the 20 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.