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
24 changes: 24 additions & 0 deletions .devcontainer/consumer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
// Reuses docker/Dockerfile — the same image the "first-use" docker-compose
// environment (see docker/USER-GUIDE.md) builds — so both paths install the
// published package the same way, on the same base. This config does NOT
// build agentic-kit from this checkout; use the top-level
// .devcontainer/devcontainer.json for that.
"name": "agentic-kit (try the published release)",
"build": {
"dockerfile": "../../docker/Dockerfile",
"context": "../../docker"
},
"remoteUser": "tester",
"remoteEnv": {
"AK_DIST_TAG": "next"
},
"postCreateCommand": "bash ${containerWorkspaceFolder}/.devcontainer/consumer/postCreate.sh",
"forwardPorts": [7431],
"portsAttributes": {
"7431": {
"label": "ak dashboard",
"onAutoForward": "notify"
}
}
}
35 changes: 35 additions & 0 deletions .devcontainer/consumer/postCreate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Installs the PUBLISHED @pacphi/agentic-kit — not this checkout — and preps a
# scratch git repo outside the mounted workspace so `ak setup` (project scope)
# never touches the agentic-kit repo you're browsing in the editor.
set -euo pipefail

AK_DIST_TAG="${AK_DIST_TAG:-next}"
echo "installing @pacphi/agentic-kit@${AK_DIST_TAG} (published release)"
npm install -g "@pacphi/agentic-kit@${AK_DIST_TAG}"
ak --version

SANDBOX="$HOME/sandbox"
mkdir -p "$SANDBOX"
cd "$SANDBOX"
if [ ! -d .git ]; then
git init -q
git config user.email "tester@codespace.invalid"
git config user.name "Codespace Tester"
echo "# sandbox — try agentic-kit here" > README.md
git add README.md
git commit -qm "init sandbox"
fi

cat <<EOF

Ready. In the integrated terminal:
cd ~/sandbox
ak setup --yes # drop --yes to see the interactive prompts
ak status
ak dashboard --no-open --port 7431 # open the printed #token URL via the Ports tab

Pin a specific release instead of next: rebuild with AK_DIST_TAG set in this
devcontainer.json's "remoteEnv", or inside the container:
npm install -g @pacphi/agentic-kit@4.0.0-alpha.41 && ak sync
EOF
29 changes: 29 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "agentic-kit (source / maintainer)",
"image": "mcr.microsoft.com/devcontainers/typescript-node:22-bookworm",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
},
// pnpm is pinned via package.json's "packageManager" field; corepack reads
// that automatically. `npm link` exposes `ak`/`agentic-kit` globally,
// pointing at THIS checkout — edits are live, no reinstall needed.
// corepack/npm link write into the image's root-owned global bin dir
// (/usr/local/bin), so those two steps need sudo; `node` has passwordless
// sudo in this base image. `pnpm install` targets the (UID-synced,
// node-writable) mounted repo and stays unprivileged.
"postCreateCommand": "sudo corepack enable && pnpm install && sudo npm link && ak --version",
"forwardPorts": [7431],
"portsAttributes": {
"7431": {
"label": "ak dashboard",
"onAutoForward": "notify"
}
},
"customizations": {
"vscode": {
"extensions": ["dbaeumer.vscode-eslint", "davidanson.vscode-markdownlint"]
}
},
"remoteUser": "node"
}
110 changes: 110 additions & 0 deletions .github/workflows/devcontainers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: devcontainers

# Builds and smoke-tests both dev container configs with the reference
# devcontainer CLI — the same tool Codespaces/VS Code use — so a config
# change is proven before merge (PR trigger) and upstream drift (base image
# tags, the published npm package's install path) is caught even when
# nothing in this repo changed (monthly schedule). See docs/DEVCONTAINERS.md.

on:
pull_request:
paths: &all-paths
- '.devcontainer/**'
- 'docker/Dockerfile'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'bin/**'
- 'src/**'
- '.github/workflows/devcontainers.yml'
push:
branches: [main]
paths: *all-paths
schedule:
# Monthly: dev container definitions change rarely, but the base image
# tag and the published package they install can drift independently.
- cron: '23 6 1 * *'
workflow_dispatch:

jobs:
# Narrows the two jobs below to only what each one actually depends on, so
# a docker/Dockerfile-only change (consumer) doesn't rebuild the maintainer
# config and vice versa. Scheduled/manual runs always exercise both — that
# is the point of the monthly drift check, there is no diff to filter on.
changes:
name: detect relevant changes
runs-on: ubuntu-latest
outputs:
maintainer: ${{ steps.filter.outputs.maintainer || 'true' }}
consumer: ${{ steps.filter.outputs.consumer || 'true' }}
steps:
- uses: actions/checkout@v7
if: github.event_name == 'pull_request' || github.event_name == 'push'
- uses: dorny/paths-filter@v3
id: filter
if: github.event_name == 'pull_request' || github.event_name == 'push'
with:
filters: |
maintainer:
- '.devcontainer/devcontainer.json'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'bin/**'
- 'src/**'
- '.github/workflows/devcontainers.yml'
consumer:
- '.devcontainer/consumer/**'
- 'docker/Dockerfile'
- '.github/workflows/devcontainers.yml'

maintainer:
name: maintainer devcontainer (build from this checkout)
needs: changes
if: needs.changes.outputs.maintainer == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

# `up` runs postCreateCommand (corepack enable && pnpm install && npm
# link), then runCmd proves `ak` actually resolved to THIS checkout —
# not a stale global — before running the fast surface test.
- name: Build + smoke test
uses: devcontainers/ci@v0.3
with:
configFile: .devcontainer/devcontainer.json
push: never
runCmd: |
set -euo pipefail
linked=$(ak --version)
pkg=$(node -p "require('./package.json').version")
echo "ak --version: ${linked}"
echo "package.json: ${pkg}"
case "${linked}" in
*"${pkg}"*) ;;
*) echo "npm link did not resolve to this checkout" >&2; exit 1 ;;
esac
pnpm run test:surface

consumer:
name: consumer devcontainer (published release)
needs: changes
if: needs.changes.outputs.consumer == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

# `up` runs postCreate.sh (npm install -g the published package, seeds
# ~/sandbox); runCmd checks the CLI is reachable and the sandbox exists.
- name: Build + smoke test
uses: devcontainers/ci@v0.3
with:
configFile: .devcontainer/consumer/devcontainer.json
push: never
runCmd: |
set -euo pipefail
which ak
ak --version
ak --help --all > /dev/null
test -d "$HOME/sandbox/.git"
echo "sandbox present at $HOME/sandbox"
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ Git revisions, and contributor links have different package footprints while
[Installation and scope](docs/INSTALLATION.md) before choosing a non-global method
or deploying on a shared machine.

Want to try it before installing anything locally? Open this repo in GitHub
Codespaces (or any [dev container](https://containers.dev)-compatible tool) —
a "try the published release" configuration installs `ak` into a disposable
container for you. See [docs/DEVCONTAINERS.md](docs/DEVCONTAINERS.md).

**What you get:**

- **One command** installs + heals + *proves* ruflo & agentic-qe — native SQLite, memory, security, statusline (past npm's `allow-scripts` gate).
Expand Down Expand Up @@ -259,6 +264,9 @@ tarball, Git, and source-checkout installs, including user/machine/project impac
[docs/HOST-SUPPORT.md](docs/HOST-SUPPORT.md) — Claude, Codex, and OpenCode support
across Ruflo, AQE, and RuvNet Brain, with limitations and current upstream risks.

[docs/DEVCONTAINERS.md](docs/DEVCONTAINERS.md) — Codespaces/dev container setup,
both for contributing to this repo and for trying the published release.

[docs/DASHBOARD.md](docs/DASHBOARD.md) — dashboard navigation, deep links, keyboard behavior, and
the meaning of each primary and secondary view.

Expand Down
6 changes: 6 additions & 0 deletions docker/USER-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ containers, and the containers cannot alter your host install. Persistent
state lives only in Docker-managed named volumes; the single bind mount is
`./artifacts` inside this directory.

Prefer an editor-attached environment (Codespaces, VS Code Dev Containers) over
a bare `docker compose` shell? The consumer dev container in
[`.devcontainer/consumer/`](../.devcontainer/consumer/devcontainer.json) builds
this same Dockerfile and installs the same published package — see
[docs/DEVCONTAINERS.md](../docs/DEVCONTAINERS.md) for the tradeoffs.

## Prerequisites

- Docker Desktop (macOS/Windows) or Docker Engine + Compose v2 (Linux).
Expand Down
145 changes: 145 additions & 0 deletions docs/DEVCONTAINERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Dev containers (Codespaces and compatible tools)

Two dev container configurations ship in `.devcontainer/`, for two different
audiences. Both work in GitHub Codespaces and in any tool that reads the
[dev container spec](https://containers.dev) (VS Code's Dev Containers
extension, JetBrains Gateway, `devcontainer` CLI).

| Config | Audience | What it gives you |
| --- | --- | --- |
| `.devcontainer/devcontainer.json` | Contributors to this repo | Node + pnpm, `pnpm install`, `ak`/`agentic-kit` linked to **this checkout** via `npm link` — edit source, run `ak` immediately, no reinstall |
| `.devcontainer/consumer/devcontainer.json` | Anyone who wants to try `ak` without cloning | Installs the **published** `@pacphi/agentic-kit` npm package into a disposable container, same image [docker/](../docker/) uses |

The top-level config is the default: "Create codespace on main" from the
GitHub UI uses it. To get the consumer config instead, use the "..." menu →
"New with options" → pick "agentic-kit (try the published release)" (or, with
the `devcontainer` CLI, pass `--config .devcontainer/consumer/devcontainer.json`).

## CI

[.github/workflows/devcontainers.yml](../.github/workflows/devcontainers.yml)
builds and smoke-tests both configs with the
[`devcontainers/ci`](https://github.com/devcontainers/ci) action — the same
`devcontainer` CLI Codespaces uses, not a hand-rolled approximation. A
`changes` job (via `dorny/paths-filter`) narrows each config's job to the
files it actually depends on, so, for example, a `docker/Dockerfile` edit
only rebuilds the consumer config, not the maintainer one:

| Job | Runs when | Proves |
| --- | --- | --- |
| `maintainer` | `.devcontainer/devcontainer.json`, `package.json`, `pnpm-lock.yaml`, `pnpm-workspace.yaml`, `bin/**`, or `src/**` changes | `npm link` resolves `ak` to the checked-out source (version string match), then `pnpm run test:surface` |
| `consumer` | `.devcontainer/consumer/**` or `docker/Dockerfile` changes | The published package installs and `~/sandbox` is seeded |

Both jobs also run monthly (`23 6 1 * *`, no path filter — that's the point:
catch a base-image tag disappearing or a published-package install breaking
even when nothing here changed) and on demand via `workflow_dispatch`.

## Maintainer container

```bash
# GitHub UI: Code -> Codespaces -> Create codespace on main
# VS Code: Dev Containers: Reopen in Container
```

`postCreateCommand` runs `corepack enable && pnpm install && npm link`.
`packageManager` in `package.json` pins the pnpm version, so corepack
resolves it without a separate install step. `npm link` registers the
`ak`/`agentic-kit` bins globally, pointing at `bin/agentic-kit.mjs` in the
container's copy of your checkout — so `ak status` (or any `ak` command)
exercises your live edits, not a published version.

Base image: `mcr.microsoft.com/devcontainers/typescript-node:22-bookworm`
(Node 22, the `engines` floor in `package.json`; CI additionally matrixes
Node 24 and 26 — see [.github/workflows/ci.yml](../.github/workflows/ci.yml)).
Features: GitHub CLI (`gh`) and Docker-outside-of-Docker, so you can drive
`gh pr`/`gh issue` and run the [docker/](../docker/) first-use environment
from inside the codespace.

Standard checks, unchanged from local development:

```bash
pnpm test # unit suite + statusline/dashboard/admin tests
pnpm run check # typecheck + lint + markdown lint + build + test
```

The `claude` CLI (required for `ak setup`) is deliberately **not**
auto-installed — it needs an interactive device-flow login tied to your own
Anthropic account, which doesn't belong in `postCreateCommand`. Install it
yourself when you want to exercise setup end to end:

```bash
npm install -g @anthropic-ai/claude-code
claude # complete the login flow, then:
ak setup
```

## Consumer container ("try the published release")

Reuses [docker/Dockerfile](../docker/Dockerfile) — the same image the
[first-use docker-compose environment](../docker/USER-GUIDE.md) builds — so a
Codespace and a local `docker compose up` install the kit the same way, on
the same base. It does **not** build agentic-kit from source; the repo
checkout is present in the editor for reference only.

`postCreateCommand` runs
[`.devcontainer/consumer/postCreate.sh`](../.devcontainer/consumer/postCreate.sh):
it installs `@pacphi/agentic-kit@next` globally, then creates
`~/sandbox` — a throwaway git repo outside the mounted workspace — so
`ak setup`'s project-scope work (`ruflo init --full --force`, statusline,
project config) never touches the agentic-kit repo you're browsing.
When it finishes, the terminal shows the next commands:

```bash
cd ~/sandbox
ak setup --yes # drop --yes to see the interactive prompts
ak status
ak dashboard --no-open --port 7431 # open the printed #token URL via the Ports tab
```

Pin a specific release instead of `next` by editing `AK_DIST_TAG` in
`.devcontainer/consumer/devcontainer.json`'s `remoteEnv` before creating the
container, or after creation:

```bash
npm install -g @pacphi/agentic-kit@4.0.0-alpha.41 && ak sync
```

### The dashboard port

`ak dashboard` binds `127.0.0.1` only, by design
([ADR-0014](adr/0014-dashboard-auth-and-remediation.md)). Unlike a plain
`docker compose up` on your host — which needs the `socat` bridge documented
in [docker/MAINTAINER-GUIDE.md](../docker/MAINTAINER-GUIDE.md) to reach a
container-loopback listener — a dev container's port forwarding runs from
*inside* the container (VS Code Server attaches there directly), so
forwarding container port 7431 works without a bridge. Open the "Ports" tab
and use the forwarded URL, appending the `#token=...` fragment printed by
`ak dashboard`.

## Choosing between a dev container and `docker compose`

Both routes end up running the published package in a disposable container;
they exist for different workflows:

- **This directory's consumer config** — editor-attached (files, terminal,
extensions, port forwarding through the VS Code UI), one container per
Codespace/window, `ak setup` run by hand so you see the real prompts.
- **[docker/](../docker/)** — a scripted, fully non-interactive
(`--yes`) environment meant for release smoke-testing, bisecting a
regression across dist-tags, and upgrade-path testing; no editor
attachment. See [docker/USER-GUIDE.md](../docker/USER-GUIDE.md) and
[docker/MAINTAINER-GUIDE.md](../docker/MAINTAINER-GUIDE.md).

## Limitations

- `ak setup --codex --opencode` (the flag set a maintainer might reach for)
offers the ~2 GB RuvNet Brain download; on a metered or slow Codespaces
network, pass `--no-ruvnet-brain` or accept the default prompt to skip it.
- Codespaces machine types with less than the default disk/CPU may time out
during `pnpm install` (maintainer container) or during `ak setup`
(consumer container, if you opt into RuvNet Brain); pick a larger machine
type from the Codespaces creation options if you hit this.
- Docker-outside-of-Docker in the maintainer container shares the host
Codespace's Docker daemon; containers you start from `docker/` there are
visible to (and stoppable from) the Codespace host, same as any
Docker-outside-of-Docker setup.
Loading