PORTAL / LIBRARY / improve-queue

[ OPERATIONS · OPERATOR UTILITY ]

/improve-queue

Run the improvement-queue auto-implementer.

Download the skill file (.md)

Placeholders like ACME Agency, <id> and you@example.com mark values that are per-agency — your install fills them with YOUR clients and accounts. If a section references a helper script you don't have yet, it ships with that workflow's install.

/improve-queue — daily auto-improver

Closes the loop on the improvement queue. Colleagues' sandboxed Claude sessions write proposals to ~/scratch/improvements/; the root aggregator (17:00 Sarajevo) bundles them to a Drive doc + #your-channel post AND drops a machine-readable /opt/improvements/pending/<date>.json. This skill is the step that used to be manual ("Faris pastes the doc and says apply this") — it reads those bundles and acts on them.

When to trigger

How to run it

This skill is a thin wrapper around the orchestrator. When invoked:

  1. Run the orchestrator from the repo root:
  1. Relay the digest it prints (auto-applied / would-apply / held-for-ACME Agencyw / already-live / needs-attention). The orchestrator also posts the digest to #your-channel.

Do not hand-edit the queue state. The orchestrator owns git + Slack + the gate.

Triage boundary (who decides what)

Triage is deterministic and defaults to MANUAL on any doubt (triage() in improver.mjs):

ProposalDecision
Landing-page edit (any category — touches websites/ or describes a live-lander copy/CSS/section/sub-page change)bounced → "route via /landing-edit"
doc-gap (CLAUDE.md / SKILL.md / *.md text)auto
client-config (clients.json / config JSON backfill)auto
bug, severity low/medium, scoped to a single skill:, no infra/spend keywordauto
bug that is high-severity, has no skill, or mentions infra/secret/spendmanual
new-skill / feature-request / processmanual

Infra/spend keywords that force a bug to manual: .env, secret/token/credential, oauth/password, bridge, clickup_executor, sandbox_guard, preflight, aggregator, ecosystem, meta_lead_ads / meta ad / ad set / campaign / pixel / spend, google ads, billing/payment, webhook, git push.

Landing edits are bounced before triage (isLandingEditProposal() in improver.mjs): a proposal that touches websites/ or describes a change to a deployed lander never enters the auto-apply path — it's held with a "route via /landing-edit" reason and no worker is spawned. Landing edits must go through /landing-edit (auto-deploy, no approval); a sandbox session that writes one as an improvement proposal has bypassed that path. websites/ is also a separate repo and can't be committed from the main repo regardless. Incident: 2026-06-19.

Safety gate (the real guardrail — enforced in code, not by the LLM)

For every auto item the orchestrator:

  1. requires a clean tracked working tree on main before starting (else it skips the whole run and Slacks why);
  2. spawns an apply-one worker (see contract below) to make the edit;
  3. re-derives the actually-changed files from git (ignores the worker's self-report) and reverts + reclassifies to manual if any file matches the PROTECTED denylist — .env, .git, .claude/hooks, the bridge, the ClickUp executor, anything under shared/improvement_queue or shared/your server_setup, run_claude_subprocess.mjs, ecosystem.config.*, meta_lead_ads.mjs / meta_web_leads.mjs / google_ads_optimize.mjs, anything under websites/ (separate repo + gitignored here — landing edits go through /landing-edit, never a proposal), or any secret/credential/token path;
  4. runs node --check on every changed JS file and JSON.parse on every changed JSON file — any failure reverts the item;
  5. only then (live mode) commits that one proposal and pushes.

Each proposal starts from a clean tree and ends clean (committed-in-live, or reverted-in-shadow/blocked/failed/commit-failed), so items never bleed into each other. A commit/push that fails reverts its own changes too — otherwise the dirty files leaked into the next proposal's git add and cascaded the failure (incident 2026-06-19).

Apply-one worker contract

The orchestrator spawns one claude -p worker per auto proposal (sandbox:false, Max auth). Its rules (also embedded in the spawn prompt):

Architecture

colleague sandbox sessions → ~/scratch/improvements/*.md
        │  (root cron 17:00)
        ▼
aggregator.mjs → Drive doc + #your-channel post + /opt/improvements/pending/<date>.json (0644)
        │  (faris cron 17:30)
        ▼
improver.mjs (this skill) → triage → apply-one worker → GATE → commit+push (live) / diff+revert (shadow) → digest
        │  (deploy cron, 60s)
        ▼
/opt/agency-os updated → colleagues' clones sync

State: ~/.improver/improver-state.jsonl (one line per processed fingerprint, in faris's home so the cron needs no root). Pending bundles are READ from /opt/improvements/pending/ (world-readable, written by the root aggregator). Kill switch: touch ~/.improver/improver.disabled.

Deploy (as faris, no sudo): the improver needs no root — /opt/agency-os auto-pulls every 60s, and faris's own clone + crontab are user-writable.

cd ~/agency-os && git pull
bash shared/your server_setup/install_improver_cron.sh        # shadow (default)
# …after ~a week of clean digests:
bash shared/your server_setup/install_improver_cron.sh --live

Tuning

Rollout

Ships in shadow mode. Watch ~a week of digests (it shows exactly what it would auto-apply and what it holds), confirm the classifier, then flip to --live.