Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
34c1ba2
Update Archon configuration and setup documentation
ibuildthings-instrumentl Apr 17, 2026
96e2c71
Merge pull request #1 from instrumentl/initial-changes
ibuildthings-instrumentl Apr 17, 2026
37b691b
docs: design for @archie Slack feature-to-review-app workflow
ibuildthings-instrumentl Apr 17, 2026
97ea2b3
docs(plans): implementation plan for @archie slack feature-to-review-app
ibuildthings-instrumentl Apr 17, 2026
1dba9e2
feat(scripts): dispatch-review-app helper for slack feature workflow
ibuildthings-instrumentl Apr 17, 2026
686d7da
feat(scripts): ci-wait helper with hard timeout
ibuildthings-instrumentl Apr 17, 2026
28b7ad5
feat(scripts): fetch-review-app-url helper
ibuildthings-instrumentl Apr 17, 2026
eccb49f
feat(workflows): archon-slack-feature-to-review-app
ibuildthings-instrumentl Apr 17, 2026
a4d7e8c
feat(workflows): register archon-slack-feature-to-review-app as bundled
ibuildthings-instrumentl Apr 17, 2026
3019ace
feat(workflows): add plan-approval gate to slack-feature-to-review-app
ibuildthings-instrumentl Apr 17, 2026
7aa843a
feat(slack): add Block Kit approve + request-changes UI for loop gates
ibuildthings-instrumentl Apr 17, 2026
453cf46
Merge pull request #2 from instrumentl/slack-yolo-integration
ibuildthings-instrumentl Apr 17, 2026
2ec6b4e
Merge pull request #3 from instrumentl/slack-gate-blockkit
ibuildthings-instrumentl Apr 17, 2026
0596934
feat(slack): ack incoming messages with :eyes: reaction immediately
ibuildthings-instrumentl Apr 17, 2026
e7c30e1
Merge pull request #4 from instrumentl/slack-receipt-ack
ibuildthings-instrumentl Apr 17, 2026
bb19356
fix(deps): bump flatted to >=3.4.2 via override (Dependabot #19)
ibuildthings-instrumentl Apr 20, 2026
2e0f7d5
Merge pull request #5 from instrumentl/fix/dependabot-flatted
ibuildthings-instrumentl Apr 20, 2026
1e4f6f9
fix(deps): bump axios to ^1.15.0 via override (#29, #30)
ibuildthings-instrumentl Apr 20, 2026
1e6c4e0
Merge pull request #9 from instrumentl/fix/dependabot-axios
ibuildthings-instrumentl Apr 20, 2026
f11a43d
feat(slack): implement Slack scoping questions modal for structured i…
ibuildthings-instrumentl Apr 20, 2026
721b8bb
feat(slack): add structured scoping-question modal for spec loop
ibuildthings-instrumentl Apr 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .archon/commands/defaults/scout-consolidate-perf-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
description: Merge per-route Scout profiles into a single implementation plan (plan.md)
argument-hint: (no arguments)
---

# Consolidate Scout performance plan

**Workflow ID**: $WORKFLOW_ID
**Artifacts**: $ARTIFACTS_DIR

---

## Mission

Read:

- `$ARTIFACTS_DIR/routes.json`
- `$ARTIFACTS_DIR/routes-summary.md`
- `$ARTIFACTS_DIR/profile-00.md` … `$ARTIFACTS_DIR/profile-09.md` (include only files that exist; skipped indices may say SKIPPED)

Produce **one** implementation plan at **`$ARTIFACTS_DIR/plan.md`** that `archon-plan-setup` / `archon-confirm-plan` / `archon-implement-tasks` can consume.

---

## Plan template (required sections)

Use this structure (fill with real content from profiles):

```markdown
# Performance: Scout hot-route optimizations

## Summary
{1–2 sentences}

## Mission
{Single goal statement}

## NOT Building (Scope Limits)
- {Explicit non-goals — e.g. unrelated refactors, new features}
- Do not change behavior except latency/resource usage unless noted.

## Success Criteria
- [ ] Each targeted route has measurable improvement or documented tradeoff
- [ ] Project validation suite passes (see CLAUDE.md)
- [ ] Scout shows no new regressions for these endpoints after deploy (verification note)

## Files to Change

| File | Action |
|------|--------|
| `{path}` | UPDATE |

## Patterns to Mirror

| Pattern | Source File | Lines |
|---------|-------------|-------|
| {name} | `{path}` | {lines} |

## Task List

### Task 1: {title}
**Action**: UPDATE
**Details**: {specific changes}
**Route**: `{METHOD} {path}`
**Validate**: {command}

### Task 2: ...

(Add one or more tasks per route or grouped fix.)

## Validation Commands
1. Commands from CLAUDE.md / package.json (typecheck, lint, test).

## Risks

| Risk | Impact | Mitigation |
|------|--------|------------|
| {risk} | {H/M/L} | {mitigation} |
```

---

## Rules

1. **Deduplicate** overlapping tasks if multiple profiles touch the same file.
2. **Order** tasks by dependency (models before handlers, shared utils first).
3. **Reference** actual symbols/files from the profile markdown files.
4. If profiles disagree, prefer the most evidence-backed recommendation and note the conflict in **Risks**.
5. Ignore profiles that are SKIPPED or empty.

---

## Output

- Write **`$ARTIFACTS_DIR/plan.md`** only (plan-setup will create `plan-context.md`).
- Stdout: `Plan written to $ARTIFACTS_DIR/plan.md with {N} tasks.`
Comment on lines +83 to +96
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add a hard guard for zero usable profiles.

If routes.json is [] or every profile-XX.md is SKIPPED/empty, this can still write a valid-looking plan.md with 0 tasks, allowing the implementation pipeline to continue on an empty plan. Make that case explicit: do not produce plan.md; emit a clear failure message instead.

Suggested command contract addition
 ## Rules
 
 1. **Deduplicate** overlapping tasks if multiple profiles touch the same file.  
 2. **Order** tasks by dependency (models before handlers, shared utils first).  
 3. **Reference** actual symbols/files from the profile markdown files.  
 4. If profiles disagree, prefer the most evidence-backed recommendation and note the conflict in **Risks**.  
 5. Ignore profiles that are SKIPPED or empty.
+6. If there are **zero** usable profiles or `routes.json` is empty, do not write `plan.md`; print `ERROR: no Scout routes/profiles available to consolidate` and stop.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Rules
1. **Deduplicate** overlapping tasks if multiple profiles touch the same file.
2. **Order** tasks by dependency (models before handlers, shared utils first).
3. **Reference** actual symbols/files from the profile markdown files.
4. If profiles disagree, prefer the most evidence-backed recommendation and note the conflict in **Risks**.
5. Ignore profiles that are SKIPPED or empty.
---
## Output
- Write **`$ARTIFACTS_DIR/plan.md`** only (plan-setup will create `plan-context.md`).
- Stdout: `Plan written to $ARTIFACTS_DIR/plan.md with {N} tasks.`
## Rules
1. **Deduplicate** overlapping tasks if multiple profiles touch the same file.
2. **Order** tasks by dependency (models before handlers, shared utils first).
3. **Reference** actual symbols/files from the profile markdown files.
4. If profiles disagree, prefer the most evidence-backed recommendation and note the conflict in **Risks**.
5. Ignore profiles that are SKIPPED or empty.
6. If there are **zero** usable profiles or `routes.json` is empty, do not write `plan.md`; print `ERROR: no Scout routes/profiles available to consolidate` and stop.
---
## Output
- Write **`$ARTIFACTS_DIR/plan.md`** only (plan-setup will create `plan-context.md`).
- Stdout: `Plan written to $ARTIFACTS_DIR/plan.md with {N} tasks.`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.archon/commands/defaults/scout-consolidate-perf-plan.md around lines 83 -
96, The consolidation step currently allows creating $ARTIFACTS_DIR/plan.md with
0 tasks; add a hard guard in the consolidation logic that reads routes.json and
the collected profile-XX.md inputs (and any plan-context.md produced by
plan-setup) to detect the "zero usable profiles" case (routes.json == [] OR all
profiles are SKIPPED/empty). If that condition is true, do NOT write
$ARTIFACTS_DIR/plan.md, exit with a non-zero status, and emit a clear failure
message on stdout/stderr such as "No usable profiles found — aborting plan
generation" instead of "Plan written to $ARTIFACTS_DIR/plan.md with {N} tasks."
Ensure this check runs before any file write and references the same artifacts
(routes.json, profile-XX.md, plan-context.md, $ARTIFACTS_DIR/plan.md) used
elsewhere so callers get a deterministic failure rather than an empty plan file.

67 changes: 67 additions & 0 deletions .archon/commands/defaults/scout-discover-routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
description: Query Scout APM for top slow + high-traffic routes and write routes.json
argument-hint: "[optional app name or app id — else first active app]"
---

# Scout route discovery

**User message**: $ARGUMENTS
**Artifacts**: $ARTIFACTS_DIR

---

## Mission

Use **Scout MCP** tools to identify **up to 10 HTTP routes** to optimize. Combine:

- **Slowest** endpoints (p95 / mean response time), and
- **Most hit** (throughput / request volume)

Dedupe by route identity (method + path). If you have fewer than 10 distinct hot/slow routes, include the next candidates by severity. If Scout returns fewer than 10, use all available.

---

## Prerequisites

1. **MCP**: Scout tools should be available (`list_apps`, `get_app_endpoints`, `get_endpoint_metrics`, etc.). If MCP is unavailable, ask the user to set `SCOUT_API_KEY`, ensure Docker can run `scoutapp/scout-mcp-local`, or paste a Scout endpoints export into `$ARTIFACTS_DIR/scout-endpoints-export.json` (array of endpoint objects) and continue from that file.

2. **App selection**: If `$ARGUMENTS` names an app or numeric id, use that. Otherwise call `list_apps` and pick the production app that matches this repo (name/hostname) or the most recently active app. State which app you chose.

Comment on lines +24 to +29
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fail closed when Scout input is unavailable.

This runs before the interactive review gate, so “ask the user to set SCOUT_API_KEY or paste an export” can complete without producing routes.json. Prefer: use $ARTIFACTS_DIR/scout-endpoints-export.json if it already exists; otherwise write an empty routes.json plus an error summary and stop the workflow path explicitly.

Suggested prompt contract
-1. **MCP**: Scout tools should be available (`list_apps`, `get_app_endpoints`, `get_endpoint_metrics`, etc.). If MCP is unavailable, ask the user to set `SCOUT_API_KEY`, ensure Docker can run `scoutapp/scout-mcp-local`, or paste a Scout endpoints export into `$ARTIFACTS_DIR/scout-endpoints-export.json` (array of endpoint objects) and continue from that file.
+1. **MCP**: Scout tools should be available (`list_apps`, `get_app_endpoints`, `get_endpoint_metrics`, etc.). If MCP is unavailable, first check whether `$ARTIFACTS_DIR/scout-endpoints-export.json` already exists and continue from that file. If it does not exist, write `routes.json` as `[]`, write `routes-summary.md` with setup instructions, print `ERROR: Scout MCP unavailable and no endpoints export found`, and stop without inventing routes.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Prerequisites
1. **MCP**: Scout tools should be available (`list_apps`, `get_app_endpoints`, `get_endpoint_metrics`, etc.). If MCP is unavailable, ask the user to set `SCOUT_API_KEY`, ensure Docker can run `scoutapp/scout-mcp-local`, or paste a Scout endpoints export into `$ARTIFACTS_DIR/scout-endpoints-export.json` (array of endpoint objects) and continue from that file.
2. **App selection**: If `$ARGUMENTS` names an app or numeric id, use that. Otherwise call `list_apps` and pick the production app that matches this repo (name/hostname) or the most recently active app. State which app you chose.
## Prerequisites
1. **MCP**: Scout tools should be available (`list_apps`, `get_app_endpoints`, `get_endpoint_metrics`, etc.). If MCP is unavailable, first check whether `$ARTIFACTS_DIR/scout-endpoints-export.json` already exists and continue from that file. If it does not exist, write `routes.json` as `[]`, write `routes-summary.md` with setup instructions, print `ERROR: Scout MCP unavailable and no endpoints export found`, and stop without inventing routes.
2. **App selection**: If `$ARGUMENTS` names an app or numeric id, use that. Otherwise call `list_apps` and pick the production app that matches this repo (name/hostname) or the most recently active app. State which app you chose.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.archon/commands/defaults/scout-discover-routes.md around lines 24 - 29, The
current flow allows continuing without Scout data; change the logic so the
command first checks for $ARTIFACTS_DIR/scout-endpoints-export.json and uses it
if present, but if it is not present then create an empty routes.json, write a
clear error summary (mention missing SCOUT_API_KEY and absence of scout
endpoints export) into the artifacts, and explicitly stop the workflow path
(fail-closed) rather than proceeding to call list_apps/get_app_endpoints; update
any branching that previously asked the user to “ask the user to set
SCOUT_API_KEY” to this fail-closed behavior and reference variables/commands
like $ARTIFACTS_DIR/scout-endpoints-export.json, routes.json, SCOUT_API_KEY,
$ARGUMENTS, list_apps, get_app_endpoints to locate where to change the logic.

---

## Steps

1. Call Scout MCP to list endpoints with metrics for the chosen app (`get_app_endpoints` or equivalent).

2. Rank and select up to **10** routes using a clear rule, e.g.:
- Take top **5** by p95 latency (or worst mean response time if p95 missing).
- Take top **5** by throughput.
- Union, dedupe, then fill remaining slots by composite score: `latency × log(throughput)` or similar.

3. Write **`$ARTIFACTS_DIR/routes.json`** — JSON array of exactly the chosen routes, each object including at least:

- `rank` (1–10)
- `method` (e.g. `GET`)
- `path` (e.g. `/api/foo`)
- `scout_name` or endpoint id if the API exposes one
- `p95_ms`, `mean_ms` (numbers or null)
- `rpm` or throughput (number or null)
- `error_rate` if available

4. Write **`$ARTIFACTS_DIR/routes-summary.md`** — human-readable table: rank, method, path, p95, throughput, notes.

5. Print a one-line stdout summary: `Discovered N routes for app {name} (id {id}).`

---

## Error handling

- If no endpoints are returned: write `routes.json` as `[]`, explain in summary, and STOP with a clear error in stdout so the workflow can fail visibly.

---

## Success criteria

- `routes.json` exists and is valid JSON.
- `routes-summary.md` exists.
- At most 10 routes; each profile step can rely on fixed indices `0..N-1`.
3 changes: 3 additions & 0 deletions .archon/config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
worktree:
baseBranch: dev
# Copy local .env into isolated worktrees so Scout MCP sees SCOUT_API_KEY when cwd is ~/.archon/workspaces/...
copyFiles:
- .env
Comment on lines +3 to +5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Copying .env into every worktree propagates all secrets, not just SCOUT_API_KEY.

The comment explains this is needed so Scout MCP sees SCOUT_API_KEY when Archon runs from ~/.archon/workspaces/.... But copyFiles: [.env] copies the whole file — SLACK_BOT_TOKEN, DB credentials, API keys for every provider — into each worktree directory, which then lives under ~/.archon/workspaces/... and may be picked up by unrelated subprocesses, backed up, or leaked via logs/artifacts if a workflow later archives the worktree. Consider:

  1. Using a narrower mechanism (e.g. a .env.scout file with only SCOUT_API_KEY, or passing the var through the worktree env rather than copying the file), or
  2. Documenting the blast radius in this comment and ensuring worktree cleanup reliably removes .env copies.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.archon/config.yaml around lines 3 - 5, The config currently copies the
entire .env via the copyFiles: - .env setting which exposes all secrets into
each worktree; change this to only propagate SCOUT_API_KEY (either by creating
and copying a minimal .env.scout containing just SCOUT_API_KEY or by injecting
SCOUT_API_KEY into the worktree environment instead of copying the file), and if
you keep copying ensure the comment near copyFiles documents the blast radius
and add a reliable cleanup step to remove copied .env files from worktrees;
focus your edits on the copyFiles setting and surrounding comment in
.archon/config.yaml and any worktree creation/cleanup logic that handles copied
files.


docs:
path: packages/docs-web/src/content/docs
70 changes: 70 additions & 0 deletions .archon/scripts/ci-wait.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bun
/**
* Wait for GitHub CI on a PR to finish, with a hard wall-clock timeout.
*
* Usage: bun .archon/scripts/ci-wait.js <pr-number-or-url> [timeout-ms]
*
* Exit codes:
* 0 — all required checks passed
* 1 — at least one required check failed
* 3 — timeout reached before CI finished
* 2 — bad args / missing gh
*
* Used by archon-slack-feature-to-review-app to gate review-app deploy.
*/
import { spawn } from 'node:child_process';

const DEFAULT_TIMEOUT_MS = 60 * 60 * 1000;

function main() {
const [pr, timeoutArg] = process.argv.slice(2);

if (!pr) {
console.error('Usage: ci-wait.js <pr-number-or-url> [timeout-ms]');
process.exit(2);
}

const timeoutMs = timeoutArg ? Number(timeoutArg) : DEFAULT_TIMEOUT_MS;
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
console.error(`Invalid timeout-ms: ${timeoutArg}`);
process.exit(2);
}

console.log(
`Waiting for CI on PR ${pr} (timeout: ${Math.round(timeoutMs / 1000)}s)...`
);

const child = spawn(
'gh',
['pr', 'checks', pr, '--watch', '--fail-fast', '--interval', '30'],
{ stdio: 'inherit' }
);

let timedOut = false;
const timer = setTimeout(() => {
timedOut = true;
console.error(`\nCI wait timed out after ${Math.round(timeoutMs / 1000)}s`);
child.kill('SIGTERM');
setTimeout(() => process.exit(3), 2000).unref();
}, timeoutMs);
timer.unref();

child.on('exit', (code, _signal) => {
clearTimeout(timer);
if (timedOut) return;
if (code === 0) {
console.log('CI passed.');
process.exit(0);
}
console.error(`CI failed (gh exit code ${code ?? 'null'})`);
process.exit(1);
});

child.on('error', err => {
clearTimeout(timer);
console.error(`Failed to spawn gh: ${err.message}`);
process.exit(2);
});
}

main();
47 changes: 47 additions & 0 deletions .archon/scripts/dispatch-review-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bun
/**
* Dispatch a GitHub Actions workflow_dispatch event on the given ref.
*
* Usage: bun .archon/scripts/dispatch-review-app.js <workflow-file> <ref>
*
* Exits 0 on successful dispatch. Exits non-zero with a human-readable stderr
* message on any failure (missing args, gh not installed, gh call failed).
*
* Used by the archon-slack-feature-to-review-app workflow after CI passes
* to deploy a review app for the PR branch.
*/
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';

const execFileAsync = promisify(execFile);

async function main() {
const [workflowFile, ref] = process.argv.slice(2);

if (!workflowFile || !ref) {
console.error('Usage: dispatch-review-app.js <workflow-file> <ref>');
process.exit(2);
}

try {
const { stdout, stderr } = await execFileAsync('gh', [
'workflow',
'run',
workflowFile,
'--ref',
ref,
]);
if (stdout.trim()) console.log(stdout.trim());
if (stderr.trim()) console.log(stderr.trim());
console.log(
JSON.stringify({ dispatched: true, workflow: workflowFile, ref })
);
} catch (err) {
console.error(
`Failed to dispatch ${workflowFile} on ref ${ref}: ${err.stderr ?? err.message}`
);
process.exit(1);
}
}

void main();
Loading