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
13 changes: 13 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Worked adapter examples

Concrete, sanitized `.claude/gates.json` + `CLAUDE.md` pairs for real stacks, to copy from when you
[fill in your own adapter](../docs/GETTING_STARTED.md#step-3--fill-in-claudegatesjson-the-adapter--the-important-one).
Each subdirectory is one stack; the `gates.json` there is what you'd drop into your repo's `.claude/gates.json`.

| Example | Stack | Highlights |
|---|---|---|
| [`ts-solidity-foundry/`](ts-solidity-foundry/) | TypeScript (pnpm workspace) **+** Solidity (Foundry) monorepo | Gates that span two toolchains; a module map mixing `packages/*` (TS) and `contracts/` (Foundry); mixed-stack `test_affected`; which artifacts to gitignore vs track. |

> These are **references, not runnable projects** — they show the adapter shape and the decisions a mixed
> stack forces, not a buildable tree. Adapt the paths and commands to your repo, then verify each gate runs
> (`bash .claude/scripts/gate.sh build`, etc.).
43 changes: 43 additions & 0 deletions examples/ts-solidity-foundry/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# acme-protocol

> Worked example `CLAUDE.md` for the [`ts-solidity-foundry`](./) adapter. Sanitized; adapt to your repo.
> Keep this file lean — project-WIDE context only. Task detail belongs in the task prompt.

## What this project is
On-chain lending protocol. Solidity contracts hold the logic; a TypeScript SDK wraps them and a web app
consumes the SDK. Users interact through the web app; integrators use the SDK.

## Stack & layout
- Language / runtime: TypeScript (Node 20) + Solidity 0.8.x
- Package manager: pnpm (workspace) for TS; Foundry (`forge`) for contracts
- Key directories (mirror `.claude/gates.json` → `modules`):
- `packages/sdk/` — TS client SDK wrapping the contracts (consumes the generated ABI)
- `packages/web/` — front-end app, consumes `sdk`
- `contracts/` — Foundry project: `.sol` sources, `test/`, deploy scripts, `foundry.toml`

## Conventions
- Code style / lint: eslint + prettier for TS; `forge fmt` for Solidity (checked in CI via `forge fmt --check`).
- Testing: vitest per TS package (`test` script); `forge test` for contracts. Tests live beside sources
(`*.test.ts`) and in `contracts/test/*.t.sol`.
- Definition of done: `build`, `lint`, `typecheck`, `test` all green; contract changes keep `forge coverage`
≥ threshold; reviewers approve (security lens required for `contracts`).

## Multi-agent orchestration
This repo is set up for orchestrated multi-agent development. See `docs/USAGE.md`.
- **Adapter:** `.claude/gates.json` — module map, gate commands, model routing. Keep it current.
- **Gates run via** `.claude/scripts/gate.sh <name>` and the hooks in `.claude/settings.json`.

### Module boundaries (hard rule)
A worker assigned to a module MUST NOT edit files outside that module's `path`.
- The **ABI** that `sdk` consumes is a *build artifact* of `contracts` — regenerate it via `build`, never by
hand-editing across the boundary. If an SDK change needs a contract change, the orchestrator re-scopes it as
two coordinated sub-tasks (contracts first, then sdk), not one worker reaching across.
- `web` depends on `sdk`'s published types; same rule — cross-package changes are re-scoped, never reached.

### Merge policy
`pr-per-agent` — base branch `main`.

## Don'ts
- Don't put secrets (RPC URLs, deployer keys, mnemonics) in the repo — use `.env` (gitignored).
- Don't bypass the gates.
- Don't commit build artifacts — see the example README for the gitignore split.
81 changes: 81 additions & 0 deletions examples/ts-solidity-foundry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# TypeScript + Solidity (Foundry) monorepo — worked adapter

A reference [`gates.json`](gates.json) + [`CLAUDE.md`](CLAUDE.md) for a **pnpm workspace + Foundry** monorepo:
several TS packages plus a `contracts/` Foundry project. It exists because the first real adaptation of this
template to a mixed stack hit a handful of stack-specific decisions a JS-only example doesn't surface. Those
decisions, and how this example resolves them:

## 1. Gates that span two toolchains
Each gate runs the TS side, then the Foundry side, and fails if **either** fails:

```jsonc
"build": "pnpm -r build && (cd contracts && forge build)",
"test": "pnpm -r test && (cd contracts && forge test)",
"lint": "pnpm -r lint && (cd contracts && forge fmt --check)",
```

- `&&` (not `;`) so a red TS build short-circuits before forge runs and the gate's exit code is honest.
- `(cd contracts && …)` in a **subshell** — forge must run inside its own project dir (where `foundry.toml`
lives), but the subshell keeps `gate.sh`'s working dir at the repo root for the next gate.
- `typecheck` is TS-only (Solidity's compile *is* its typecheck, already covered by `forge build`).
- `coverage` combines `pnpm -r coverage` with `forge coverage --report summary`; keep one
`coverage_threshold` that both must clear, or split into per-stack tickets if they diverge.

## 2. A module map mixing TS packages and a Foundry dir
```jsonc
"modules": [
{ "name": "sdk", "path": "packages/sdk" },
{ "name": "web", "path": "packages/web" },
{ "name": "contracts", "path": "contracts" }
]
```
Each `path` is a **non-overlapping worker boundary**. The subtlety in a mixed stack is the **generated ABI**:
`sdk` consumes an ABI produced from `contracts`. That ABI is a *build artifact*, not a shared source file — so:

- A worker in `contracts` edits `.sol` and regenerates the ABI via `build`.
- A worker in `sdk` consumes the committed/generated ABI but **never edits `contracts`**.
- If a feature needs both (new contract method + SDK wrapper), the orchestrator splits it into two coordinated
sub-tasks (contracts → then sdk), rather than letting one worker cross the boundary. This keeps the isolation
guarantee that makes parallel workers safe.

## 3. `test_affected` for this stack
`test_affected` runs on the `Stop` hook after every change, so it should be fast:

```jsonc
"test_affected": "pnpm --filter \"...[origin/main]\" test && (cd contracts && forge test)"
```

- **TS side:** `pnpm --filter "...[origin/main]"` runs only packages changed since `origin/main` (plus their
dependents). This needs `origin/main` present in the worktree — a per-worktree setup hook should
`git fetch origin main` first, or the filter silently matches nothing. (See the `test_affected` guidance in
[`docs/GETTING_STARTED.md`](../../docs/GETTING_STARTED.md#choosing-test_affected-per-stack).)
- **Foundry side:** `forge` has **no** native since-base filter, so run the full `forge test`. Contract suites
are usually fast enough to run whole; if not, split by directory with `forge test --match-path`.
- If in doubt, `test_affected` = your full `test` is always a correct (if slower) default.

## 4. Artifacts: gitignore vs track
```gitignore
# TS
node_modules/
packages/*/dist/

# Foundry
contracts/out/ # compiled artifacts — regenerated by `forge build`
contracts/cache/
contracts/broadcast/ # deploy tx logs — noise; keep only if you need an on-chain audit trail

# Secrets
.env
```
- **Ignore** compiled output (`out/`, `dist/`, `cache/`) — it's reproducible from `build`.
- **Track** the generated **ABI/types** that `sdk` imports *if* you want SDK builds to work without first
compiling contracts (common for CI speed and for downstream consumers). Otherwise generate it in `build` and
ignore it. Pick one and state it in `CLAUDE.md` so workers don't thrash.
- **Track** `foundry.toml`, `remappings.txt`, and the lockfiles (`pnpm-lock.yaml`); **never** track `.env`.

## Using it
1. Copy [`gates.json`](gates.json) → your repo's `.claude/gates.json`; fix module `path`s and gate commands to
match your layout.
2. Copy [`CLAUDE.md`](CLAUDE.md) → your repo root; trim to your project.
3. Verify each gate actually runs: `bash .claude/scripts/gate.sh build` (and `lint`, `test`, …).
4. Follow [`docs/GETTING_STARTED.md`](../../docs/GETTING_STARTED.md) from Step 4 on.
66 changes: 66 additions & 0 deletions examples/ts-solidity-foundry/gates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"_README": "WORKED EXAMPLE (not a live adapter) — a TypeScript (pnpm workspace) + Solidity (Foundry) monorepo. Copy this into YOUR repo's .claude/gates.json and adapt paths/commands. See examples/ts-solidity-foundry/README.md for the reasoning behind each choice. Empty string = gate skipped, not failed.",

"project": {
"name": "acme-protocol",
"language": "typescript+solidity",
"packageManager": "pnpm"
},

"modules": [
{
"name": "sdk",
"path": "packages/sdk",
"description": "TypeScript client SDK that wraps the contracts. Depends on the ABI produced by `contracts`, but a worker here edits only TS — never the .sol sources.",
"owner": ""
},
{
"name": "web",
"path": "packages/web",
"description": "Front-end app (consumes `sdk`). TS/TSX only.",
"owner": ""
},
{
"name": "contracts",
"path": "contracts",
"description": "Foundry project: Solidity sources, tests, and deploy scripts. A worker here edits .sol + foundry config only. Regenerating the ABI that `sdk` consumes is a build-time artifact, not a cross-module edit.",
"owner": ""
}
],

"gates": {
"_note": "Run from repo root. Each mixed-stack gate runs the TS side then the Foundry side; a failure in either fails the gate. `(cd contracts && ...)` keeps forge in its own project dir without a persistent chdir.",
"install": "pnpm install --frozen-lockfile && (cd contracts && forge install)",
"build": "pnpm -r build && (cd contracts && forge build)",
"lint": "pnpm -r lint && (cd contracts && forge fmt --check)",
"typecheck": "pnpm -r typecheck",
"test": "pnpm -r test && (cd contracts && forge test)",
"test_affected": "pnpm --filter \"...[origin/main]\" test && (cd contracts && forge test)",
"coverage": "pnpm -r coverage && (cd contracts && forge coverage --report summary)",
"coverage_threshold": 80,
"e2e": "",
"security": "(cd contracts && slither . || true)"
},

"review": {
"lenses": ["correctness", "tests", "security", "performance"],
"consensus": "all",
"_consensus_note": "Solidity handles value — keep the `security` lens on. 'all' = every lens must approve.",
"skills": []
},

"budget": {
"orchestrator_model": "opus",
"worker_model": "sonnet",
"explorer_model": "haiku",
"reviewer_model": "opus",
"max_parallel_workers": 3,
"_note": "3 modules → up to 3 parallel workers. Drop to 2 if human review/merge is the bottleneck."
},

"merge": {
"policy": "pr-per-agent",
"_policy_options": "pr-per-agent | orchestrated-sequential-merge",
"baseBranch": "main"
}
}
Loading