Skip to content
Open
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
7 changes: 7 additions & 0 deletions .alignfirst.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"schemaVersion": 1,
"ticketPattern": "^\\d+$",
"plans": {
"folder": "alignfirst"
}
}
5 changes: 5 additions & 0 deletions .changeset/alcode-projects-and-alignfirst.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@paleo/alcode": minor
---

Added `projects`, replacing `@paleo/alproject`. `new --no-ticket` and the delegated prompt run the `alignfirst` CLI, now a prerequisite. Removed `reserve-side-ticket`.
5 changes: 5 additions & 0 deletions .changeset/alignfirst-initial-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"alignfirst": minor
---

Initial release of the AlignFirst CLI.
5 changes: 5 additions & 0 deletions .changeset/docmap-embedded-commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@paleo/docmap": minor
---

The CLI can be embedded with an injected command prefix.
5 changes: 5 additions & 0 deletions .changeset/workspace-port-claim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@paleo/workspace": minor
---

The kernel checks `portRange` in `.alignfirst.json` against the port scheme.
9 changes: 3 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@ This repository is on *GitHub*.

## Packages

- `@paleo/alcode` — coding agent wrapper for the AlignFirst developer.
- `@paleo/alproject` — local project registry for the AlignFirst developer
- `alignfirst` — the AlignFirst CLI: protocols, plans and docs
- `@paleo/alcode` — coding agent wrapper and project discovery for the AlignFirst Developer
- `@paleo/docmap` — lightweight documentation system for AI agents and humans
- `@paleo/openclaw-channel-mock-core` — shared library for synthetic OpenClaw channel plugins (bus, actions, factories)
- `@paleo/openclaw-slack-mock` — Slack-shaped channel plugin for test scenarios
- `@paleo/openclaw-discord-mock` — Discord-shaped channel plugin for test scenarios
- `@paleo/openclaw-test` — Dockerised regression-test harness (bus, scenario driver, judge, Compose stack)
- `@paleo/plans-share` — share the `.plans` directory through a team plans repository
- `@paleo/workspace` — run multiple git-worktree dev environments side by side

## Docmap - Seek Documentation
Expand All @@ -42,9 +41,7 @@ A **workspace** is a git worktree (with its branch) plus its own dev setup: syml

Run `npm run workspace -- --guide` for the full procedures.

## AlignFirst - Ticket ID, Commit Message, Branch Name

_Ticket ID_: Format is numeric. Use the ticket ID if explicitly provided. Otherwise, deduce it from the current branch name (no confirmation needed). If the branch name is unavailable, get it via `git branch --show-current`. Only ask the user as a last resort.
## AlignFirst - Commit Message, Branch Name

Commit message convention: we use conventional commit, e.g., `feat: add new feature`. Do not mention the ticket ID. Do not add a "Co-Authored-By:" line.

Expand Down
2 changes: 2 additions & 0 deletions DEVELOPERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Run `npm run workspace -- --guide` to learn the full procedures.

## Everyday commands

The tooling runs through the `alignfirst` CLI built in this workspace, so run `npm run build` first.

| Command | Purpose |
|---------|---------|
| `npm run build` | Build every package |
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ Companion products for AI-assisted software work. They can be used independently
## AlignFirst skills

Collaborative spec/plan/AAD/merge/review protocols. See [alignfirst-skills.md](alignfirst-skills.md).
The protocols run through the `alignfirst` CLI. Install it with `npm install -g alignfirst`; see
[the CLI README](packages/alignfirst/README.md).

### Team plans repository

`@paleo/plans-share` shares the `.plans` directory of the AlignFirst skills among a team, through a dedicated plans repository. See [packages/plans-share/README.md](packages/plans-share/README.md).
`alignfirst plans setup` and `alignfirst sync` share the `.plans` directory among a team through a
dedicated plans repository. See [the CLI README](packages/alignfirst/README.md).

## Docmap - Agent-discoverable documentation

Expand All @@ -33,6 +36,7 @@ AlignFirst Developer is an AI teammate for software work, currently packaged on
Our `alignfirst-setup-guide` skill can help to install these tools. Temporarily install the skill (globally or locally):

```bash
npm install -g alignfirst
npx skills add https://github.com/paleo/alignfirst --skill alignfirst-setup-guide
```

Expand Down
9 changes: 3 additions & 6 deletions alignfirst-developer-tests/.env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,9 @@ OPENCLAW_WORKSPACE_DIR=./workspace
# gateway's baked copy so playbook edits iterate without a rebuild (relative to this dir).
ALIGNFIRST_DEVELOPER_PLAYBOOK_SKILL_DIR=../skills/alignfirst-developer-openclaw-playbook

# Required: host path to the built @paleo/alcode package (the coding-delegation CLI the
# gateway runs; its --guide is the delegation manual). Build it first:
# `npm run build --workspace @paleo/alcode` from the repo root, so packages/alcode/dist
# exists. Live-mounted read-only at /opt/alcode (guide edits in templates/ iterate live);
# a /usr/local/bin/alcode wrapper on PATH resolves to it.
ALIGNFIRST_CODE_DIR=../packages/alcode
# Required: host path to the monorepo root. Run `npm run build` there first so the
# mounted alcode, alignfirst, and docmap packages have built output.
ALIGNFIRST_REPO_DIR=..

# Required: coding agent launched by alcode inside the gateway. Codex is the recommended primary
# harness path. This does not select the OpenClaw conversation model.
Expand Down
28 changes: 13 additions & 15 deletions alignfirst-developer-tests/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,21 @@ USER root
# Fixture runtime deps (git for `git init` / worktree, curl for the playbook's
# verification step — "confirm the app still serves" — pnpm via Corepack for
# the project's dev scripts). Plus the per-command mock-cli shim symlinks
# this consumer wants intercepted. `claude`, `codex`, `gh`, and `alproject` are shimmed. `alcode` runs for real,
# this consumer wants intercepted. `claude`, `codex`, and `gh` are shimmed. `alcode` runs for real,
# and its selected coding-agent subprocess resolves back to the shim via PATH order.
RUN apk add --no-cache git curl && \
corepack enable && corepack prepare pnpm@latest --activate && \
for name in claude codex gh alproject; do ln -sf mock-cli-shim "/opt/openclaw-test/mocks/bin/$name"; done && \
mkdir -p /home/claw/projects /home/claw/external-projects /home/claw/lifecycle-projects && \
chown claw:claw /home/claw/projects /home/claw/external-projects \
/home/claw/lifecycle-projects
for name in claude codex gh; do ln -sf mock-cli-shim "/opt/openclaw-test/mocks/bin/$name"; done && \
mkdir -p /home/claw/projects && \
chown claw:claw /home/claw/projects

# PATH wrapper for the real `@paleo/alcode` CLI. The package's built output is
# live-mounted at /opt/alcode (`${ALIGNFIRST_CODE_DIR}:/opt/alcode:ro` in the compose
# overlay), so alcode edits iterate without a rebuild — mirroring the skill
# live-mount. `/usr/local/bin` sits after `/opt/openclaw-test/mocks/bin` in
# PATH, so this wrapper is only reached for `alcode` (never shimmed), while
# alcode's own coding-agent subprocess still hits the shim.
RUN printf '#!/bin/sh\nexec node /opt/alcode/bin/alcode.mjs "$@"\n' > /usr/local/bin/alcode && \
chmod +x /usr/local/bin/alcode
# PATH wrappers for the real CLIs. `/opt/alignfirst` is the read-only monorepo root
# mount, so @paleo/docmap, arktype, and semver resolve through its root node_modules.
# `alcode projects` spawns `alignfirst`. The mocked coding agent never runs the stub
# skills, so no `npx -y alignfirst` resolution is needed.
RUN printf '#!/bin/sh\nexec node /opt/alignfirst/packages/alcode/bin/alcode.mjs "$@"\n' > /usr/local/bin/alcode && \
printf '#!/bin/sh\nexec node /opt/alignfirst/packages/alignfirst/bin/alignfirst.mjs "$@"\n' > /usr/local/bin/alignfirst && \
chmod +x /usr/local/bin/alcode /usr/local/bin/alignfirst

# PATH wrapper for the `openclaw` CLI. OpenClaw is only a local npm dependency
# of /opt/openclaw-test/src (nothing puts its node_modules/.bin on the exec
Expand Down Expand Up @@ -81,8 +79,8 @@ RUN npm ci --include=dev && \
npm cache clean --force

# Single fixture template baked into the image. scripts/reset-fixture.mjs copies
# from here to each configured fixture parent at scenario start, materializing the
# distinct projects (nimbus, lumen, and external-parent orion) with per-name patches.
# from here into the nested fixture tree at scenario start, materializing nimbus,
# lumen, and external-team project orion with per-name patches.
COPY --chown=claw:claw projects-fixture/template/ /opt/alignfirst-developer-tests/fixtures/template/
RUN cd /opt/alignfirst-developer-tests/fixtures/template && \
pnpm install --frozen-lockfile --prod=false
Expand Down
24 changes: 12 additions & 12 deletions alignfirst-developer-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ This README only documents what is specific to this harness.
cp .env.local.example .env.local
# Edit .env.local — fill ANTHROPIC_API_KEY and select ALIGNFIRST_CODE_AGENT

# Build the real alcode CLI the gateway runs (packages/alcode/dist must exist).
npm run build --workspace @paleo/alcode --prefix ..
# Build the real alcode and alignfirst CLIs the gateway runs.
npm run build --prefix ..

npm run vendor # build + pack the local @paleo/openclaw-* into vendor/ (first run only; env:build repeats it)
npm install
Expand All @@ -43,36 +43,36 @@ See the upstream README for all flags. `--parallel K` (or `OPENCLAW_TEST_PARALLE

Then set `OPENCLAW_CODEX_HOME` in `.env.local` to `$PWD/.codex-home` with `$PWD` expanded to its absolute value. Repeat the login when the stored access token expires.
- `ALIGNFIRST_DEVELOPER_PLAYBOOK_SKILL_DIR` — host path to the `alignfirst-developer-openclaw-playbook` skill, bind-mounted into the gateway. Playbook edits iterate live, no rebuild.
- `ALIGNFIRST_CODE_DIR` — host path to `packages/alcode` (build it first). Live-mounted read-only at `/opt/alcode`; the `/usr/local/bin/alcode` wrapper runs `node /opt/alcode/bin/alcode.mjs`. Alcode runs for real, while both `claude` and `codex` resolve to the mock through PATH. Delegation instructions come from `alcode --openclaw-guide` (rendered from `templates/`, so guide edits iterate live).
- `ALIGNFIRST_REPO_DIR` — host path to the monorepo root (build it first). Live-mounted read-only at `/opt/alignfirst`; the `alcode` and `alignfirst` wrappers run both CLIs from the checkout. Alcode runs for real, while both `claude` and `codex` resolve to the mock through PATH. Delegation instructions come from `alcode --openclaw-guide` (rendered from `packages/alcode/templates/`, so guide edits iterate live).
- `ALIGNFIRST_CODE_AGENT=codex|claude` — required selector for alcode's child. It does not affect the OpenClaw conversation model. `ALIGNFIRST_CODE_MODELS` optionally narrows the agent models or pins a full Codex slug.
- [`docker-compose.yml`](docker-compose.yml) — shared fixture volumes on gateway + runner at `/home/claw/projects`, `/home/claw/external-projects`, and `/home/claw/lifecycle-projects`; the skill + alcode bind mounts on `gateway`; `OPENCLAW_TEST_JUDGE_MODEL=anthropic/claude-haiku-4-5` on `runner`.
- [`docker-compose.yml`](docker-compose.yml) — one shared fixture volume on gateway + runner at `/home/claw/projects`; the skill and monorepo bind mounts on `gateway`; `OPENCLAW_TEST_JUDGE_MODEL=anthropic/claude-haiku-4-5` on `runner`.

## Fixtures

Each scenario starts fresh: [`scripts/reset-fixture.mjs`](scripts/reset-fixture.mjs) (run via `ctx.execInGateway(...)`) materializes three Git repositories on `main`, copied from the committed [`projects-fixture/template/`](projects-fixture/template/). `nimbus` and `lumen` live under `/home/claw/projects`; `orion` lives under the second explicit fixture parent `/home/claw/external-projects`. Each carries a project-specific package name, `README.md` and `DEVELOPERS.md` headings, port block (6500, 6520, and 6540), and an untracked `.plans/` directory for alcode's project gate.
Each scenario starts fresh: [`scripts/reset-fixture.mjs`](scripts/reset-fixture.mjs) (run via `ctx.execInGateway(...)`) materializes three Git repositories on `main`, copied from the committed [`projects-fixture/template/`](projects-fixture/template/). `nimbus` and `lumen` live under `/home/claw/projects`; `orion` lives under `/home/claw/projects/external-projects`. Each project has `.alignfirst.json`, a project-specific package name, `README.md` and `DEVELOPERS.md` headings, its own 20-port block (6500, 6520, and 6540), and an untracked `.plans/` directory.

`/home/claw/lifecycle-projects` resets to an empty allowed parent. The creation scenario uses it for `nova`, isolated from the standard projects. Removal scenarios seed a real linked `nimbus` workspace and a sibling additional directory after reset.
The root and its nested `external-projects` and `lifecycle-projects` directories carry `.alignfirst-projects.json` markers with descriptions and port ranges. The lifecycle directory resets empty; the creation scenario uses it for `nova`. Removal scenarios seed a real linked `nimbus` workspace and a sibling additional directory after reset.

The absolute parents are harness storage details. Scenarios obtain canonical main paths from the mocked `alproject list` result and pass those paths through starter, workspace, and coding-agent assertions. The `alproject` shim emits the CLI's labelled list format, supports per-scenario project records and additional-directory groups, and records argv, cwd, and call order. Lifecycle scenarios configure guide, registration, and unregistration responses; successful mutations update subsequent list output.
`alcode projects` runs for real against the fixture tree and calls `alignfirst config --json` in each child. Scenarios assert on the agent's exec calls and on the filesystem.

## Scenarios

Drop `scenarios/<id>.ts`, default-export `async (ctx: ScenarioContext) => void`. Shared helpers under `scenarios/_lib/` (skipped by the runner's discovery). Current scenarios: `A01`–`A26`.
Drop `scenarios/<id>.ts`, default-export `async (ctx: ScenarioContext) => void`. Shared helpers under `scenarios/_lib/` (skipped by the runner's discovery). Current scenarios: `A01`–`A21` and `A23`–`A26`.

Almost every one starts with `bootstrapThreadFromChannel` (`_lib/thread-bootstrap.ts`): it sends the channel message, waits for the starter, and asserts the channel session stopped right there — one thread post, no second one, no worktree on disk, no coding-agent call, nothing substantive leaked to the channel root. `sendInThread` then wakes the thread session, which owns the actual work. A scenario that seeds a worktree first passes its absolute path as `seededWorktreePaths` so the check still catches anything the channel session created.

`A10` exercises the real `alcode` foreground run driven as an OpenClaw background exec and rejects direct Claude or Codex launches. `A11` covers an explicit user hold. `A12` chains two delegations in one thread, exposing the heartbeat-cooldown wake gate. `A13` drives alcode directly for deterministic selected-agent new/resume coverage and Codex failure handling. The shared mock serves a bundled Codex model catalog and both agents' JSONL protocols.

`A06` pins first-turn lookup caching across two off-project messages. `A14` covers sole-project inference, `A15` duplicate-name path selection, and `A16` carries an external canonical path through workspace setup and delegation.

`A17` creates and registers `nova`, bootstraps it on `main` without an AlignFirst protocol, and checks the initial commit. `A18` confirms exact paths before removing a linked workspace and its main worktree. `A19` makes workspace removal fail on an uncommitted file and checks that filesystem and registry state remain intact.
`A17` creates and prepares `nova`, bootstraps it on `main` without an AlignFirst protocol, and checks the initial commit. `A18` confirms exact paths before removing a linked workspace and its main worktree. `A19` makes workspace removal fail on an uncommitted file and checks that the filesystem and project config remain intact.

`A23` resolves a PR URL through review and its reported outcome. `A24` carries a multi-project base refresh through one no-protocol delegation per project. `A25` captures a detailed request before workspace setup and coding. `A26` reserves the next side ticket `side-N` before workspace setup for explicit no-ticket work.

Rebuild the alcode package and harness image before focused coverage:
Rebuild the CLIs and harness image before focused coverage:

```sh
npm run build --workspace @paleo/alcode --prefix ..
npm run build --prefix ..
npm run env:build

ALIGNFIRST_CODE_AGENT=codex npm run e2e -- --channel discord-mock A13-alcode-agent-contract
Expand All @@ -96,6 +96,6 @@ This harness always tests the **local** `@paleo/openclaw-*` sources, never npmjs

- [`openclaw.json`](openclaw.json) · [`docker-compose.yml`](docker-compose.yml) · [`Dockerfile`](Dockerfile) · [`package.json`](package.json) · [`scripts/vendor-packages.mjs`](scripts/vendor-packages.mjs) — committed.
- `vendor/` (gitignored) — locally-built `@paleo/openclaw-*` tarballs, regenerated by `npm run vendor`.
- `.env.local` (gitignored) — API keys, workspace/skill/alcode paths, and `ALIGNFIRST_CODE_AGENT`.
- `.env.local` (gitignored) — API keys, workspace/skill/repository paths, and `ALIGNFIRST_CODE_AGENT`.
- `artifacts/` (gitignored) — per-run outputs.
- `.gateway-logs/` (gitignored) — `raw-stream.jsonl` (opt-in). Session transcripts live in the gateway's SQLite store; each cell's artifact dir archives them as `transcripts.json`.
15 changes: 4 additions & 11 deletions alignfirst-developer-tests/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ include:
volumes:
openclaw-codex-home:
fixture-projects:
fixture-external-projects:
fixture-lifecycle-projects:

services:
gateway:
Expand All @@ -26,23 +24,18 @@ services:
volumes:
- ${OPENCLAW_CODEX_HOME:-openclaw-codex-home}:/home/claw/.codex:ro
- fixture-projects:/home/claw/projects
- fixture-external-projects:/home/claw/external-projects
- fixture-lifecycle-projects:/home/claw/lifecycle-projects
# Live-mount the playbook skill over its baked copy so playbook edits
# iterate without an image rebuild. Set in .env.local (relative to this
# dir, e.g. ../skills/alignfirst-developer-openclaw-playbook).
- ${ALIGNFIRST_DEVELOPER_PLAYBOOK_SKILL_DIR}:/home/claw/.agents/skills/alignfirst-developer-openclaw-playbook
# Live-mount the built @paleo/alcode package so the /usr/local/bin/alcode
# wrapper resolves to it. ALIGNFIRST_CODE_DIR is the host path to packages/alcode
# (build it with `npm run build` first). Read-only: the CLI only reads its
# own dist/bin/templates and spawns the selected coding agent from there.
- ${ALIGNFIRST_CODE_DIR}:/opt/alcode:ro
# Live-mount the built monorepo so the alcode and alignfirst wrappers resolve
# to this checkout. Run `npm run build` at the root first so alcode, alignfirst,
# and docmap have built output.
- ${ALIGNFIRST_REPO_DIR:?set ALIGNFIRST_REPO_DIR to the monorepo root}:/opt/alignfirst:ro

runner:
environment:
OPENCLAW_TEST_JUDGE_MODEL: anthropic/claude-haiku-4-5
ALIGNFIRST_CODE_AGENT: ${ALIGNFIRST_CODE_AGENT:?set ALIGNFIRST_CODE_AGENT to codex or claude}
volumes:
- fixture-projects:/home/claw/projects
- fixture-external-projects:/home/claw/external-projects
- fixture-lifecycle-projects:/home/claw/lifecycle-projects
Loading