Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
d111802
docs: add versioned agent-client capability matrix and policy controls
roodboi Oct 12, 2026
58c485a
fix(mcp): harden run argv and tool input contract
roodboi Oct 12, 2026
c6c0db3
fix(env): harden legacy env key files and AES-GCM envelope parsing
roodboi Oct 12, 2026
de862d7
Merge remote-tracking branch 'origin/next' into w14-rework
roodboi Oct 12, 2026
dc88c6b
Merge remote-tracking branch 'origin/next' into w06-rework
roodboi Oct 12, 2026
ffeecce
fix(agents): generate capability matrix doc and parse all guidance co…
roodboi Oct 12, 2026
56bac3a
fix(mcp): make typed refusals value-free and keep unknown-tool in-band
roodboi Oct 12, 2026
12e80af
chore: merge origin/next into wf/w15-w5-6
roodboi Oct 12, 2026
cd76b26
test(env): pin AES-GCM IV, size and tag-length guards with discrimina…
roodboi Oct 12, 2026
bcf88ec
fix(init): stop writing repo-local agent files by default
roodboi Oct 12, 2026
c005262
fix(env): resolve --env base and default the same way on every command
roodboi Oct 12, 2026
6136946
fix(agents): count corrupted and unreadable integrations as drift
roodboi Oct 12, 2026
9854d1b
test(env): pin the console logger backend for CLI refusal tests
roodboi Oct 12, 2026
6e1ff63
test(mcp): assert closed ambiguous_project refusal in project-name suite
roodboi Oct 12, 2026
1f8b51e
chore(x01): temporary witness cost trace for hosted measurement
roodboi Oct 12, 2026
0911e6d
perf(storage): coalesce witness helper work per native command
roodboi Oct 12, 2026
eb9a678
chore(x01): revert temporary witness cost trace
roodboi Oct 12, 2026
7b2ccfc
test(e2e): restore the networks scenario budget after witness coalescing
roodboi Oct 12, 2026
fa7741c
Merge remote-tracking branch 'origin/next' into wf/x03-witness-probes
roodboi Oct 12, 2026
37f093a
perf(storage): make witness engine and executable fences cheaper
roodboi Oct 12, 2026
6a4e118
chore(x03): temporary witness probe trace for hosted measurement
roodboi Oct 12, 2026
2b11ed3
fix(storage): keep closed probe cancellation for direct engine-ID fences
roodboi Oct 12, 2026
a777bc4
test(storage): pin witness fence counts and refusal controls
roodboi Oct 12, 2026
994ddb8
chore(x03): revert temporary witness probe trace
roodboi Oct 12, 2026
3edbd54
feat(agents): package offline skill references and the HACK-P pattern…
roodboi Oct 12, 2026
726cc27
test(e2e): add agent-surface-freeze negative control for guidance writes
roodboi Oct 12, 2026
9b971fa
ci: add gated Bun crash experiment and read-only crash census
roodboi Oct 12, 2026
1342871
perf(storage): read engine identity directly for docker context selec…
roodboi Oct 12, 2026
c2ecf9c
chore(x04): temporary witness probe trace for hosted measurement
roodboi Oct 12, 2026
5cf9f0f
chore(x04): revert temporary witness probe trace
roodboi Oct 12, 2026
ebe0539
test(agents): cover reference generation and reference-style and HTML…
roodboi Oct 12, 2026
6b54980
test: keep the Bun crash loop tests free of real crash reports
roodboi Oct 12, 2026
7a05b84
Merge branch 'next' into wf/w15-w5-6
roodboi Oct 12, 2026
c00468c
Merge branch 'next' into wf/w06-w5-3
roodboi Oct 12, 2026
e9b1252
Merge branch 'next' into wf/w13-w5b-2
roodboi Oct 12, 2026
af786b5
Merge branch 'next' into wf/w10-w5b-0
roodboi Oct 12, 2026
9db4dba
Merge branch 'next' into wf/w14-w5-5
roodboi Oct 12, 2026
5a731cc
Merge remote-tracking branch 'origin/wf/w06-w5-3' into train/queue-pr…
roodboi Oct 12, 2026
38d9d7f
Merge remote-tracking branch 'origin/wf/w14-w5-5' into train/queue-pr…
roodboi Oct 12, 2026
d50e935
Merge remote-tracking branch 'origin/wf/w15-w5-6' into train/queue-pr…
roodboi Oct 12, 2026
8bab674
Merge remote-tracking branch 'origin/wf/w10-w5b-0' into train/queue-p…
roodboi Oct 12, 2026
26958c9
Merge remote-tracking branch 'origin/wf/w13-w5b-2' into train/queue-p…
roodboi Oct 12, 2026
07a1834
Merge remote-tracking branch 'origin/wf/w07-w6-3' into train/queue-pr…
roodboi Oct 12, 2026
a92e3ab
Merge remote-tracking branch 'origin/wf/w02-w6-1' into train/queue-pr…
roodboi Oct 12, 2026
3e261d5
Merge remote-tracking branch 'origin/wf/w05-w6-2' into train/queue-pr…
roodboi Oct 12, 2026
6b22e00
test(patterns): add validated HACK-P01 and HACK-P02 example fixtures
roodboi Oct 12, 2026
9f20366
fix(env): write .hack/.env and the encrypted store atomically with 0600
roodboi Oct 12, 2026
10b6d73
fix(agents): point the env matrix bullet at the offline env guide
roodboi Oct 12, 2026
77da332
Merge remote-tracking branch 'origin/wf/w13-w5b-2' into train/queue-p…
roodboi Oct 12, 2026
cb665d5
fix(env): scope the env-file symlink refusal doc to write paths
roodboi Oct 12, 2026
c2b41ff
chore: merge train/queue-preview into wf/y3-envfile-b6
roodboi Oct 12, 2026
09b4e83
Merge remote-tracking branch 'origin/train/queue-preview' into wf/y4-…
roodboi Oct 12, 2026
5078855
feat(doctor): add value-free env key strength diagnostic
roodboi Oct 12, 2026
5f8cb79
fix(logger): pass messages to gum after an end-of-options marker
roodboi Oct 12, 2026
07413d0
Merge branch 'next' into wf/c4-keydiag-b7
roodboi Oct 12, 2026
6a043c0
Merge branch 'next' into wf/c6-gum-dash-b7
roodboi Oct 12, 2026
13165f9
Merge branch 'next' into wf/y4-patterns-b6
roodboi Oct 12, 2026
4243d60
Merge branch 'next' into wf/y3-envfile-b6
roodboi Oct 12, 2026
989fcea
Merge branch 'wf/c6-gum-dash-b7' into wf/y3-envfile-b6
roodboi Oct 12, 2026
c6055dd
Merge branch 'wf/y3-envfile-b6' into wf/c4-keydiag-b7
roodboi Oct 12, 2026
6a754df
Merge branch 'wf/c4-keydiag-b7' into wf/y4-patterns-b6
roodboi Oct 12, 2026
a9716aa
Merge branch 'next' into wf/y4-patterns-b6
roodboi Oct 12, 2026
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
11 changes: 11 additions & 0 deletions docs/agent-guidance.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ and domain owner; the disposition does not waive that owner's runtime gates.
`tests/pattern-catalogue.test.ts` checks completeness, CLI_SPEC command
resolution and the banned-recipe scan.

A card's `example` field names a static example project under
`examples/patterns/` (today HACK-P01 and HACK-P02). The field is contributor
reference only and is not rendered, because the plugin ships without the
repository's `examples/` tree. `tests/pattern-examples.test.ts` checks that each
reference resolves and every fixture belongs to one card. It also validates
each fixture's `hack.config.json` against the project schema and parser, the
P01 Compose file against the `locked-v1` dependency cache contract, and the P02
toolchain service against its card. Every `hack` command in a fixture README
must resolve in CLI_SPEC and name a declared service and profile. These checks
are static: they do not start containers or qualify the runtime gates.

Skill candidates and where their patterns live now:

| Candidate | Decision | Patterns live in | Promotion owner and missing contract |
Expand Down
1 change: 1 addition & 0 deletions examples/patterns/p01-dependency-bootstrap/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: pattern-p01
services:
# One-shot initializer for the immutable dependency payload (HACK-P01).
install:
image: oven/bun:1.4.2-alpine@sha256:d888c0ae6c86d7866ff10c5aafdd9077b36aee6455b33dd270fb93c0dd5cef6f
platform: linux/arm64
working_dir: /app
entrypoint: []
command: ["bun", "install", "--frozen-lockfile"]
labels:
hack.dependencies.cache-volume: dependencies
hack.dependencies.lockfiles: bun.lock
hack.dependencies.runtime-files: package.json,packages/greeting/package.json,packages/greeting/index.js
hack.dependencies.cache-protocol: locked-v1
hack.dependencies.cache-generation: "0"
hack.dependencies.cache-verify: '["bun", "-e", "require.resolve(\"greeting\")"]'
volumes:
- ..:/app
- dependencies:/app/node_modules

# Worktree-specific generation: always runs, owns its own output volume.
generate:
image: oven/bun:1.4.2-alpine@sha256:d888c0ae6c86d7866ff10c5aafdd9077b36aee6455b33dd270fb93c0dd5cef6f
platform: linux/arm64
working_dir: /app
command: ["bun", "scripts/generate.ts"]
depends_on:
install:
condition: service_completed_successfully
volumes:
- ..:/app
- dependencies:/app/node_modules:ro
- generated:/generated

app:
image: oven/bun:1.4.2-alpine@sha256:d888c0ae6c86d7866ff10c5aafdd9077b36aee6455b33dd270fb93c0dd5cef6f
platform: linux/arm64
working_dir: /app
command: ["bun", "src/server.ts"]
depends_on:
install:
condition: service_completed_successfully
generate:
condition: service_completed_successfully
volumes:
- ..:/app
- dependencies:/app/node_modules:ro
- generated:/generated:ro
healthcheck:
test: ["CMD", "bun", "-e", "const r = await fetch('http://127.0.0.1:3000/healthz'); process.exit(r.ok ? 0 : 1)"]
interval: 5s
timeout: 3s
retries: 12

volumes:
dependencies: {}
generated: {}
10 changes: 10 additions & 0 deletions examples/patterns/p01-dependency-bootstrap/.hack/hack.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "https://schemas.hack/hack.config.schema.json",
"name": "pattern-p01",
"dev_host": "pattern-p01.hack.local",
"logs": {
"follow_backend": "compose",
"snapshot_backend": "compose",
"clear_on_down": false
}
}
64 changes: 64 additions & 0 deletions examples/patterns/p01-dependency-bootstrap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# HACK-P01 example: one-shot dependency and generated-artifact bootstrap

Minimal project for catalogue card HACK-P01 (tracked in HACK-1145). It shows the
part of the pattern Hack supports today. The card's disposition is **partial**;
see "What this example does not prove" below.

## Layout

- `install` is a one-shot initializer. It opts into the
`hack.dependencies.cache-protocol: locked-v1` label, uses a digest-pinned
installer image with an explicit platform, keeps the default (empty)
environment, and writes only the `dependencies` volume.
- `generate` is the worktree-specific generation step. It always runs, owns its
own `generated` volume, and publishes its output by rename.
- `app` starts only after both one-shot services exit successfully. It mounts
`dependencies` and `generated` read-only and has its own health check.

Installation, generation and application readiness are separate steps. The
verifier label (`require.resolve("greeting")`) checks the real dependency the
application imports, not just a populated directory.

Set `platform` to the platform of your Docker daemon before you run it.

## Commands

Start the project and wait for the detached startup result:

```sh
hack up --json
```

Inspect service state, including the one-shot exits:

```sh
hack ps --json
```

Read the initializer's bounded log:

```sh
hack logs --no-follow --tail 100 install
```

Stop the project. Ordinary `hack down` keeps the dependency volume:

```sh
hack down
```

If an initializer attempt fails or is interrupted, find the cause, then increment
`hack.dependencies.cache-generation` in `.hack/docker-compose.yml` and run
`hack up --json` again. Do not delete protocol markers to force reuse.

## What this example does not prove

- Atomic publication of worktree-specific generated artifacts across concurrent
writers.
- Installers that need credentials or environment values. `locked-v1` refuses
explicit `environment` and `env_file` on the initializer.
- Two-worktree or interrupted-writer qualification. Those runtime gates belong to
WU07/WU11.

The static checks in `tests/pattern-examples.test.ts` validate this config and
its commands. They do not start containers.
15 changes: 15 additions & 0 deletions examples/patterns/p01-dependency-bootstrap/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions examples/patterns/p01-dependency-bootstrap/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "pattern-p01",
"private": true,
"type": "module",
"dependencies": {
"greeting": "file:./packages/greeting"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** Stand-in for an installed dependency that the application imports. */
export function greet(name) {
return `hello, ${name}`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "greeting",
"version": "1.0.0",
"type": "module",
"main": "index.js"
}
13 changes: 13 additions & 0 deletions examples/patterns/p01-dependency-bootstrap/scripts/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Worktree-specific generation step. It runs only after the shared dependency
* initializer succeeds and writes only to this instance's `generated` volume.
*/
import { rename, writeFile } from "node:fs/promises";

const target = "/generated/build-info.json";
const pending = `${target}.pending`;
const payload = `${JSON.stringify({ generatedAt: new Date().toISOString() })}\n`;

// Publish by rename so readers see a complete old or complete new file.
await writeFile(pending, payload);
await rename(pending, target);
20 changes: 20 additions & 0 deletions examples/patterns/p01-dependency-bootstrap/src/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { readFile } from "node:fs/promises";
import { greet } from "greeting";

const buildInfo = JSON.parse(
await readFile("/generated/build-info.json", "utf8")
) as { readonly generatedAt: string };

Bun.serve({
port: 3000,
fetch(request) {
const { pathname } = new URL(request.url);
if (pathname === "/healthz") {
return new Response("ok");
}
return Response.json({
message: greet("pattern-p01"),
generatedAt: buildInfo.generatedAt,
});
},
});
1 change: 1 addition & 0 deletions examples/patterns/p02-portable-toolchain/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
21 changes: 21 additions & 0 deletions examples/patterns/p02-portable-toolchain/.hack/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: pattern-p02
services:
# One-shot toolchain behind an opt-in profile (HACK-P02). There is no
# long-running application service in this project.
toolchain:
image: oven/bun:1.4.2-alpine@sha256:d888c0ae6c86d7866ff10c5aafdd9077b36aee6455b33dd270fb93c0dd5cef6f
profiles: [toolchain]
init: true
working_dir: /app
cpus: 2
mem_limit: 2g
environment:
BUN_INSTALL_CACHE_DIR: /cache/bun
volumes:
- ..:/app
- toolchain_dependencies:/app/node_modules
- toolchain_bun_cache:/cache/bun

volumes:
toolchain_dependencies: {}
toolchain_bun_cache: {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "https://schemas.hack/hack.config.schema.json",
"name": "pattern-p02",
"dev_host": "pattern-p02.hack.local"
}
48 changes: 48 additions & 0 deletions examples/patterns/p02-portable-toolchain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# HACK-P02 example: portable toolchain without an always-on application

Minimal project for catalogue card HACK-P02 (tracked in HACK-1146). It shows the
part of the pattern Hack supports today. The card's disposition is **partial**;
see "What this example does not prove" below.

## Layout

The project has no long-running application. `.hack/docker-compose.yml` declares
one one-shot `toolchain` service behind the opt-in `toolchain` profile:

- a digest-pinned tool image, so every machine runs the same Bun version;
- explicit resource bounds (`cpus`, `mem_limit`);
- separate named volumes for installed dependencies and the Bun download cache;
- no Docker socket, user home, SSH agent or credential directory mounts, and no
`env_file`. Keep project secrets out of the image build context as well.

## Commands

Install dependencies into the toolchain's own volume:

```sh
hack run --profile toolchain toolchain -- bun install --frozen-lockfile
```

Run the checks:

```sh
hack run --profile toolchain toolchain -- bun test
```

The command's own exit status is the result. Check it directly; do not pipe the
output through a filter that can hide a failed check.

The service is one-shot, so there is nothing to keep running. `hack down` keeps
the named cache volumes.

## What this example does not prove

- Cache reuse across worktrees with bounded eviction.
- A source receipt for linked worktrees, whose `.git` entry is a pointer file
rather than a directory.
- Owned cache accounting. Those runtime gates belong to WU11.

A test-only source identity override must never reach release evidence.

The static checks in `tests/pattern-examples.test.ts` validate this config and
its commands. They do not start containers.
8 changes: 8 additions & 0 deletions examples/patterns/p02-portable-toolchain/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "pattern-p02",
"private": true,
"type": "module",
"scripts": {
"check": "bun test"
}
}
7 changes: 7 additions & 0 deletions examples/patterns/p02-portable-toolchain/src/sum.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { expect, test } from "bun:test";
import { sum } from "./sum.ts";

test("sum adds every value", () => {
expect(sum([1, 2, 3])).toBe(6);
expect(sum([])).toBe(0);
});
4 changes: 4 additions & 0 deletions examples/patterns/p02-portable-toolchain/src/sum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** Tiny library code so the toolchain service has something to check. */
export function sum(values: readonly number[]): number {
return values.reduce((total, value) => total + value, 0);
}
Loading
Loading