Skip to content
Closed
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
10 changes: 10 additions & 0 deletions .dependency-cruiser.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Module boundaries for the TS side (docs/development/workflow.md). Go boundaries live in entropy.json.
module.exports = {
forbidden: [
{ name: 'no-circular', severity: 'error', from: {}, to: { circular: true } },
{ name: 'gen-is-a-leaf', severity: 'error', from: { path: '^gen/' }, to: { pathNot: '^gen/' } },
{ name: 'nothing-imports-e2e', severity: 'error', from: { pathNot: '^e2e/' }, to: { path: '^e2e/' } },
{ name: 'no-test-routes-from-prod', severity: 'error', from: { path: '^worker/src/', pathNot: '^worker/src/test/' }, to: { path: '^worker/src/test/' } }
],
options: { doNotFollow: { path: 'node_modules' }, tsPreCompilationDeps: true }
};
19 changes: 19 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Feature
<!-- One feature per PR: Fxx from feature_list.json, or "infra" with a reason. -->

## Done-test
<!-- The exact command and its result. Red before this PR, green after. -->
```
$ <test command>
E2E_MS=<n> STEPS=<k>/<k>
```

## What changed and why
<!-- Three lines at most. The diff tells the rest. -->

## Review
- [ ] `make preflight` green locally
- [ ] `feature_list.json`: only `passes` changed
- [ ] `progress.md` entry added
- [ ] Touches a protected path (schema/, worker/src/auth, worker/src/mcp, daemon/internal/{acp,run}, install.sh, .github/workflows)? If yes: fresh-context review done, Opus `GATE: PASS` at head requested
- [ ] Lesson captured in the repo (test, lint or docs/), or none surfaced
32 changes: 20 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ name: CI

on:
pull_request:
branches: [v4]
branches: [v4, "v4-*"]
merge_group:
push:
branches: [v4]
branches: [v4, "v4-*"]

concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
Expand All @@ -24,16 +24,23 @@ permissions:
jobs:
gen-drift:
runs-on: ubuntu-latest
timeout-minutes: 2
timeout-minutes: 3
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.4.4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Generated contracts match the schema
run: make check-gen
- name: Fixtures validate (ajv) and generated TS type-checks
run: make test-ts
- name: Entropy gate (budgets, ratchet, dead code, boundaries)
run: |
if [ ! -f Makefile ] || ! grep -q '^gen:' Makefile; then
echo "::notice::no 'make gen' target yet; skipping"; exit 0
fi
make gen
git diff --exit-code
git fetch --no-tags --depth=1 origin v4:refs/remotes/origin/v4 || true
make entropy

worker:
runs-on: ubuntu-latest
Expand All @@ -50,10 +57,11 @@ jobs:
timeout-minutes: 3
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Daemon, ACP and TUI tests
run: |
if [ ! -f go.mod ]; then echo "::notice::no go.mod yet; skipping"; exit 0; fi
go vet ./... && go test -race ./...
run: make test-go

install:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -85,7 +93,7 @@ jobs:
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: |
if [ ! -f worker/wrangler.toml ]; then echo "::notice::no worker/wrangler.toml yet; skipping"; exit 0; fi
if [ ! -f worker/wrangler.toml ] && [ ! -f worker/wrangler.jsonc ]; then echo "::notice::no worker/wrangler config yet; skipping"; exit 0; fi
if [ -z "$CLOUDFLARE_API_TOKEN" ]; then
echo "::warning::CLOUDFLARE_API_TOKEN secret not set yet (owner action, spec §7); preview skipped"; exit 0
fi
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
59 changes: 59 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Commonly v4

Commonly v4 is a multiplayer harness for the agents people already use. It is a pod where humans and
their Claude Code or Codex agents share tasks, ask for decisions and leave receipts.
- Backend: Cloudflare Workers, with one Durable Object per pod.
- Local agents: a headless Go daemon runs them over ACP.
- Pod tools: agents reach them through one remote MCP server.
- Client: the main check is an API-level e2e. The web client waits on docs/design/client-options.md.

## Start every session here
1. `./init.sh`: installs dependencies, runs the baseline and prints which features pass.
If the baseline is red, fix that before anything else.
2. Read `progress.md` (newest entry first) and `git log --oneline -15`.
3. Pick the first feature in `feature_list.json` with `passes: false` and no `blockedBy`. Work on that one
feature only.

## The loop, one feature at a time
- **Red first.** Write the feature's e2e test from its `steps` and watch it fail for the right reason.
Then build inward with unit tests for logic (red, green, refactor).
- **Verify at the API.** The feature's `test` command passes locally. A unit test alone never marks a
feature passing.
- **Mark it.** Set `passes: true`. That is the only edit allowed to `feature_list.json`. Never delete,
reword or reorder a feature to make it pass. If one is wrong, add a new feature and say why in
`progress.md`.
- **Commit small.** One PR per feature, base `v4`, using `.github/pull_request_template.md`.
- **Log it.** Add a `progress.md` entry: what changed, what's next, and anything surprising.
- **Compact.** Compact or clear context at feature boundaries, never mid-feature. `progress.md` is the
hand-off.

## Repo map
- `schema/`: JSON Schema, the only source of wire shapes. `schema/fixtures/` holds the examples that
every test loads.
- `gen/ts/` and `daemon/internal/protocol/gen.go`: generated by `make gen`. Never edit them by hand.
- `worker/`: the Worker, PodDO, MCP server and auth. `daemon/`: the Go daemon and ACP.
- `e2e/`: the slice tests (Go). `scripts/`: generators and checks. `docs/`: design and lessons.

## Commands
- `make gen`: regenerate contracts after editing `schema/`. Commit both.
- `make preflight`: `check-gen`, `test` and `entropy` (budgets in `entropy.json`). CI runs the same.
- `make e2e`: boots the Worker locally and runs `go test ./e2e`.
- On the fleet Mac, Go and Bun come from `~/.commonly/toolchains/v4/bin` (the Makefile adds it).
Never install anything globally.

## Rules
- **The schema is the contract.** No `oneOf`/`anyOf`/`allOf`. A union is a `type` enum plus
`x-variants`. Cross-field rules are `x-rules`, enforced and tested in `worker/`.
- **Tokens.** An agent holds only a `cmr_` run token. It never sees `cmc_`, `cmu_` or a third-party
credential. The server stamps receipts and the actor; it never trusts them from input.
- **Push wakes only.** Nothing polls. A change that only touches unaddressed agents wakes nobody.
- **Merging.** Green in the merge queue merges. Protected paths also need a fresh-context review and
an Opus `GATE: PASS` at the PR head: `schema/`, `worker/src/auth`, `worker/src/mcp`,
`daemon/internal/{acp,run}`, `install.sh` and `.github/workflows`.
- **Stay small.** Files at most 400 lines, functions at most 60, LOC caps per area. A new dependency or
module gets a note in `docs/adr/`. Each report states lines added/removed and what it deleted.
- **Lessons.** A lesson lands in the same PR, as a test, a lint rule or a `docs/` note. Never only in
private memory.
- **Stage skills.** Plan with Pocock `tdd`, review with Pocock `code-review`, and retro with pstack
`reflect` at the end of a lane. Details: `docs/development/workflow.md`;
docs map: `docs/INDEX.md`.
1 change: 1 addition & 0 deletions CLAUDE.md
42 changes: 42 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# v4 commands (build spec §4). Seats on the fleet Mac get Go and Bun from the v4-only
# toolchain prefix; CI installs them with setup-go and setup-bun.
export PATH := $(HOME)/.commonly/toolchains/v4/bin:$(PATH)

.PHONY: gen check-gen test test-ts test-go entropy preflight

node_modules: package.json bun.lock
bun install --frozen-lockfile
@touch node_modules

# Regenerate every contract from schema/. Never hand-edit gen/ or protocol/gen.go.
gen: node_modules
bun scripts/gen.mjs
gofmt -w daemon/internal/protocol/gen.go

# Fails if schema/ changed without `make gen`, or gen/ was edited by hand.
check-gen: gen
git diff --exit-code -- gen daemon/internal/protocol/gen.go
@test -z "$$(git ls-files --others --exclude-standard gen daemon/internal/protocol)" || (echo "untracked generated files; commit them"; exit 1)

test-ts: node_modules
bun scripts/check-fixtures.mjs
bun run check:types

test-go:
go vet ./...
go test -race ./...

test: test-ts test-go

# Entropy gate (docs/development/workflow.md): budgets and ratchets in entropy.json,
# dead code (knip, staticcheck, deadcode), TS module boundaries (dependency-cruiser).
STATICCHECK := honnef.co/go/tools/cmd/staticcheck@v0.8.2
DEADCODE := golang.org/x/tools/cmd/deadcode@v0.51.0
entropy: node_modules
bun run check:entropy
bun run check:dead
bun run check:boundaries
go run $(STATICCHECK) ./...
@if [ -n "$$(go list -f '{{if eq .Name "main"}}{{.ImportPath}}{{end}}' ./...)" ]; then go run $(DEADCODE) -test ./...; fi

preflight: check-gen test entropy
Loading
Loading