Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 34 additions & 0 deletions .github/workflows/skein-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: skein gate

# The same gate the worker and the coordinator run, minus anything that needs secrets. The
# coordinator looks at this once per PR; nobody polls it.
on:
pull_request:
push:
branches: [main]

concurrency:
group: skein-gate-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
Comment thread
coderabbitai[bot] marked this conversation as resolved.
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: 24
- run: npm ci --prefer-offline --no-audit --no-fund
- name: task gate (pull request)
if: github.event_name == 'pull_request'
run: scripts/skein/skein gate --from-branch --only brief,boundary,secrets,test-integrity,invariants,standard,accept
- name: standard (main)
if: github.event_name == 'push'
run: scripts/skein/skein gate --standard-only
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist
.env
*.tgz
.reviews/
.superset/config.local.json
42 changes: 42 additions & 0 deletions .skein/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"version": 1,
"name": "mento-cli",
"prefix": "CLI",
"envelope": "CLI_WORKER",
"coordinatorEnv": "CLI_COORDINATOR",
"plan": "docs/plan/wps.json",
"briefs": "docs/plan/briefs",
"vendor": "scripts/skein",
"gate": "scripts/skein/skein gate",
"baseBranch": "main",
"board": {
"type": "github",
"repo": "mento-protocol/cli"
},
"driver": {
"type": "superset"
},
"maxAgents": 6,
"install": "npm ci --prefer-offline --no-audit --no-fund",
"standard": [
"npm run build"
],
"e2e": [],
"invariants": [],
"monotonic": [],
"secretPatterns": [],
"secretAllow": [],
"worker": {
"agent": "claude",
"model": "claude-opus-5",
"effort": "high"
},
"review": {
"agent": "codex",
"model": "gpt-6-astra",
"fallbackModel": "claude-fable-5-1"
},
"readyMarker": "workspace '.*' ready",
"setupScript": ".superset/setup.sh",
"setupTimeout": 300
}
8 changes: 8 additions & 0 deletions .superset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"setup": [
"./.superset/setup.sh"
],
"teardown": [
"./.superset/teardown.sh"
]
}
40 changes: 40 additions & 0 deletions .superset/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Workspace setup for mento-cli: runs once per new worktree, in the worktree root, under
# Superset or the skein local driver (both export SUPERSET_ROOT_PATH). Idempotent; keep it
# fast. Coordinator-owned (.superset/** in the plan).
set -euo pipefail

ROOT="${SUPERSET_ROOT_PATH:-}"
WS_NAME="${SUPERSET_WORKSPACE_NAME:-workspace}"
[ -n "$ROOT" ] || { echo "SUPERSET_ROOT_PATH not set; run this via Superset or skein." >&2; exit 1; }

# 1. Env files are gitignored. By default a workspace gets only the committed `.env.example`
# (names, no secrets): a worker runs with the credentials the repo chose to give it, not
# whatever the main checkout holds. A repo that needs real values sets ENV_COPY_REAL=1
# and lists in ENV_WITHHOLD (an ERE of variable names) what must still be blanked.
ENV_COPY_REAL=0
ENV_WITHHOLD=''
Comment thread
coderabbitai[bot] marked this conversation as resolved.
copy_env() {
local rel="$1"
if [ -f "$rel" ]; then echo "env: $rel already present"
elif [ "$ENV_COPY_REAL" = 1 ] && [ -f "$ROOT/$rel" ]; then
mkdir -p "$(dirname "$rel")"
if [ -n "$ENV_WITHHOLD" ]; then sed -E "s|^($ENV_WITHHOLD)=.*|\1= # skein workspace: withheld|" "$ROOT/$rel" > "$rel"; else cp "$ROOT/$rel" "$rel"; fi
chmod 600 "$rel"; echo "env: copied $rel from main checkout${ENV_WITHHOLD:+ (withheld: $ENV_WITHHOLD)}"
elif [ -f "$rel.example" ]; then cp "$rel.example" "$rel"; echo "env: $rel created from $rel.example"
else echo "env: no $rel.example; skipping"; fi
}
for f in .env; do copy_env "$f"; done

# 2. The repo's git hooks: scripts/githooks/pre-push refuses a push to main.
git config core.hooksPath scripts/githooks

# 3. Dependencies.
npm ci --prefer-offline --no-audit --no-fund

# 4. Project-specific preparation (builds, generated code). Edit freely.
true

# Readiness marker. skein dispatch waits for this exact line before launching an agent, so a
# worker never races the install.
echo "workspace '$WS_NAME' ready"
18 changes: 18 additions & 0 deletions .superset/teardown.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Workspace teardown: stop any long-running process an agent left behind in this worktree
# (a dev server holding its port). Scoped by the process's working directory: never a
# broad pkill, which would take other workspaces' servers and the owner's with it.
ws=$(cd "${SUPERSET_WORKSPACE_PATH:-.}" 2>/dev/null && pwd -P) || exit 0
[ -n "$ws" ] && [ "$ws" != / ] || exit 0
cwd_of() { if [ -L "/proc/$1/cwd" ]; then readlink "/proc/$1/cwd"; else lsof -a -p "$1" -d cwd -Fn 2>/dev/null | sed -n 's/^n//p'; fi; }
pids=""
for pid in $(pgrep -u "$(id -u)" -f 'node|bun|deno|python|cargo|next-server|vite' 2>/dev/null); do
[ "$pid" = "$$" ] && continue
case "$(cwd_of "$pid" 2>/dev/null)" in "$ws" | "$ws"/*) pids="$pids $pid" ;; esac
done
[ -n "$pids" ] || exit 0
echo "Stopping processes running from $ws:$pids"
kill $pids 2>/dev/null
for _ in 1 2 3 4 5; do sleep 1; kill -0 $pids 2>/dev/null || exit 0; done
kill -9 $pids 2>/dev/null
exit 0
139 changes: 124 additions & 15 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,129 @@
# Mento CLI Instructions
# AGENTS.md

For any protocol-level question that crosses beyond this CLI repo, first read
the private `mento-master-context` router when the checkout is available:
Rules for every agent working in this repository. Coordinator-owned: do not edit.

This repo is mento-cli. It is built by several agents in parallel, each in its own workspace
and branch, and every claim is verified by a gate before it merges. The rules below exist so
that parallel work merges cleanly and so that no mistake reaches production, a user, or a
credential.

## Read before you write
1. Your brief: `docs/plan/briefs/<task-id>.md`. It names the paths you own and how you will be
judged.
2. `docs/plan/wps.json`: which task owns which paths, and what is coordinator-owned.
3. The project rules below, and whatever the brief lists under "Read first".

## The rules

**1. Stay inside your paths.** Change only files matching your task's `owned` globs in
`docs/plan/wps.json`. The `alwaysAllowed` entries there (lockfile, `docs/adr/DRAFT-*.md`) are always
fine. Never edit anything under `coordinatorOwned`: `AGENTS.md`, `.skein/**`,
`scripts/skein/**`, `docs/plan/**`, `.github/**`, the hooks, and the project's frozen paths. If
a shared file seems to need a change, that is a blocker to report, not an edit to make.

**2. Frozen paths are frozen.** The plan's `coordinatorOwned` list names the contract this
project builds against. If it lacks something you need, stop and report `BLOCKED` with the
exact change you propose. The coordinator applies it with a short ADR and tells running
workers to rebase.

**3. Never weaken a test to get green.** No `.skip`, `.only` or `.todo`. No `@ts-nocheck`,
no file-wide lint disables, no widened tolerances. Shared regression suites only grow; the
gate counts them. A failing test is information: fix the code or report the problem.

**4. Secrets.** Never commit `.env` or any credential. Never print, log, or put in an error
message a key, a token, a signing secret, or a user's personal data. Test data is invented.
The gate scans for committed keys; do not rely on it.

**5. Dependencies.** Add one only if your brief's work needs it, and name it in your hand-off.
Prefer what is already here. No install scripts from packages you cannot vouch for.

**6. Stay in scope.** Do what the brief says. Note improvements you spot in your hand-off
instead of making them. Do not refactor another task's code.

**7. Skills and workflows.** The coordinator uses whatever skills it likes; workers do not.
Do not invoke `/ship`, `/review`, `/qa`, or any workflow that merges, bumps versions, or opens
PRs on your behalf. Your gate is `scripts/skein/skein gate <task-id>` and nothing else.

**8. Do not poll GitHub.** Every agent shares API limits. No `gh pr checks --watch`, no loop
around `gh`. The local gate is your evidence; the coordinator watches CI.

## Project rules
**P1. `mento swap` moves real money.** Never run it without `--dry-run`, by hand or in a test.
Never create, fund, request or import a wallet key; tests use throwaway keys from
`viem/accounts` and never a keyfile from disk. A private key or keyfile path never appears in a
commit, a fixture, a log, or a hand-off.

**P2. Tests never depend on the network.** Every command talks to Celo through the SDK. A unit
test mocks the SDK (`@mento-protocol/mento-sdk`) or exercises the pure modules (`src/lib/format.ts`,
`src/lib/utils.ts`, `src/lib/errors.ts`, `src/lib/client.ts` resolution). A test that must reach
an RPC is an integration test: it skips itself with a printed reason when `MENTO_RPC_URL` is
unset, and CI never sets it.

**P3. Addresses and ABIs come from the SDK, never from memory.** This repo is the source of
truth for CLI behaviour only. Deployment addresses, ABIs and live chain state resolve through
`@mento-protocol/mento-sdk` (and, for a person with the checkout, the private
`../mento-master-context/.agents/mento-context/README.md` router). A worker in a fresh worktree
does not have that checkout: the brief inlines what a task needs, and a worker that finds itself
guessing a contract address reports `BLOCKED`.

**P4. Never publish.** `npm publish`, version bumps in `package.json`, and tags are
coordinator-only, through a PR. `prepack` runs `tsc`; do not make it do more.

**P5. `--json` output is a contract.** With `--json`, stdout carries exactly one JSON document
and nothing else; progress and warnings go to `stderr`. Human-readable output may change freely;
JSON field names may not without the brief saying so.


## Workflow
1. Read the brief and everything it lists under "Read first".
2. Work in small conventional commits (`feat(scope): …`, `fix(scope): …`, `test(scope): …`)
on your branch only.
3. Before claiming done, run the gate and make it pass:
```bash
scripts/skein/skein gate <task-id>
```
It checks a clean tree, path ownership, committed secrets, test integrity, the project's
invariants, then the standard commands, the e2e suite if configured, and your task's
acceptance commands. The coordinator and CI run the same gate, so a claim it does not
support will be rejected.
4. Push your branch and open a **draft** pull request. Names say what the work is and carry
the task id:
- **your branch** is `<type>/<slug>-<task-id>`, made for you at dispatch;
- **the pull request title** is a conventional-commit subject with the id at the end:
`fix(api): JSON 404 for unknown paths (CLI-01)`. It becomes the squashed commit on
`main`, and the plan reads it to know the task merged.

Never push to `main`, never merge, never force-push a branch that is not yours.
5. End your final message with exactly one envelope.

## Completion envelope
```text
CLI_WORKER_DONE
task: <task-id>
summary: <one-line outcome>
pr: <draft PR url>
files: <comma-separated top-level paths, or none>
checks: <the SKEIN_GATE_RESULT line, verbatim>
handoff: <what the next task or the reviewer needs to know, or none>
```
```text
../mento-master-context/.agents/mento-context/README.md
CLI_WORKER_BLOCKED
task: <task-id>
reason: <specific blocker>
needs: <the decision, access, contract change or dependency required>
```
Report `BLOCKED` early rather than working around a problem. A precise blocker is a good
outcome; a silent workaround is not.

This applies before broad repo searches for contracts, deployments, addresses,
ABIs, live on-chain state, stable supply, reserve data, monitoring/data
semantics, docs, the whitepaper, business model, or legal/risk framing. Load
only the relevant master-context card(s), then return to this repo for CLI
implementation details.

This repo is source of truth for CLI behavior, not for published deployment
addresses, generated ABIs, or current chain state. Resolve those through
`deployments-v2` and live RPC as routed by master context. When answering,
mention which master-context card you used or state that the checkout was
unavailable.
## Ambiguity
If the architecture or the contract is ambiguous or wrong, do not guess silently. Write
`docs/adr/DRAFT-<task-id>-<slug>.md` stating the context, the decision you took and its
consequences, and mention it in your hand-off. The coordinator numbers it at merge.

## Commands
```bash
npm ci --prefer-offline --no-audit --no-fund
# no standard commands detected: add typecheck/lint/test scripts
scripts/skein/skein gate <task-id>
scripts/skein/skein gate <task-id> --only boundary,secrets,test-integrity,invariants # fast static checks
```
6 changes: 6 additions & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Architecture decision records

Numbered ADRs are coordinator-owned and record why the contract or the architecture is as it
is. A worker that hits an ambiguity writes `DRAFT-<task-id>-<slug>.md` here (always allowed by
the gate), states the context, the decision it took and its consequences, and mentions it in
its hand-off. The coordinator numbers it at merge.
24 changes: 24 additions & 0 deletions docs/plan/COORDINATOR-PROMPT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Starting a coordinator

Paste the block below into a fresh Claude Code session in your own checkout of this repo.
Any number of coordinators can run at once; the board keeps you apart.

```text
You are a coordinator on mento-cli. Work is built by agents in parallel, each in its own
workspace and branch, and every claim is verified by a gate before anything merges. You
write no feature code yourself: you cut work into path-disjoint tasks, write briefs,
dispatch, verify, review, merge, and keep the record true. Other coordinators may be
working at the same time; the board is the lock, and you never touch a task someone else
holds.

Read these before doing anything, and follow them over any habit of your own:
1. AGENTS.md — the rules every worker follows.
2. docs/plan/COORDINATOR.md — your runbook; every step is a `skein` command.
3. docs/plan/wps.json — which task owns which files, and what is coordinator-owned.
4. docs/plan/ONBOARDING.md — machine setup, if this is your first session here.

Then check the machine: `skein doctor`, then `skein status` and `skein plan`.
The skein command is vendored at scripts/skein/skein; the /skein-* skills wrap it.

Then ask me what to work on, or pick from what `skein plan` says is ready.
```
Loading
Loading