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
9 changes: 3 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ Read the declaration rather than maintaining a prose copy:
`src/commands/common-input-fields.ts` and `src/commands/input-audience.ts`

Shared selector parsing and matching belongs in `@agent-device/selectors`; request cancellation
and progress in `@agent-device/capture-kit` (`request-cancel`, `request-progress`); cross-layer
contracts in `@agent-device/contracts`; CLI flags in `src/commands/cli-grammar`; cross-surface schema
composition in `src/cli-schema`.
and progress in `@agent-device/host-kit/request`; cross-layer contracts in `packages/contracts/src`;
CLI flags in `src/commands/cli-grammar`; cross-surface schema composition in `src/cli-schema`.

Resolve registry completeness failures at the missing declaration. Diagnose other gate failures
at their reported invariant; do not suppress them or add an allowlist to get a pass. Build interaction
Expand Down Expand Up @@ -87,8 +86,6 @@ under `contracts/fixtures/`.
- Tests mirror source topology one-to-one. Split a source module and its test together; do not add to
the legacy `interaction.test.ts` or platform `index.test.ts` aggregations. Pure moves carry their
tests unchanged; rename-only hunks owe no new coverage.
- `src/daemon/handlers/session.ts` is already over budget; extract the relevant platform-specific
concept before adding behavior.

## Toolchain and worktree traps

Expand All @@ -104,7 +101,7 @@ under `contracts/fixtures/`.

## Runtime and diagnostics seams

Diagnostics use `@agent-device/capture-kit/diagnostics`. Request diagnostics belong in the session request log;
Diagnostics use `@agent-device/host-kit/diagnostics`. Request diagnostics belong in the session request log;
session artifact paths come from `src/daemon/session-artifact-paths.ts`. App/device logs remain in `app.log`;
Apple runner and xcodebuild output remains in `runner.log`.

Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ reviewable change. Detailed testing and device procedures live in the linked foc

Requirements:

- Node.js 22 or newer
- Node.js 22.13 or newer — the pinned pnpm requires it. The published package keeps a lower
`engines.node` floor of 22.12, which CI verifies separately on the installed tarball.
- pnpm at the version pinned in `package.json`
- Android SDK tools (`adb`) for Android work
- Xcode (`simctl`/`devicectl`) for Apple-platform work
Expand Down
2 changes: 1 addition & 1 deletion docs/adr/0019-request-bound-platform-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ there, not about retiring the directory.

**Entry-to-platform hop count.** Corrected 2026-09-03, re-measured for #2278 at `27a97ee619`:
the counting definition, ordered chains, hop roles, and commit for this measurement are in
[`0019-end-state-hop-trace.md`](./0019-end-state-hop-trace.md), which supersedes the numbers
[`0023-end-state-hop-trace.md`](./0023-end-state-hop-trace.md), which supersedes the numbers
below. A file-by-file re-trace at HEAD measured 41 hops for `press`/Android and 47/49 hops
(shared 30 plus 17/19 per arm) for `snapshot`/iOS, which is now a dual-arm route (in-simulator
AX bridge primary, XCTest runner fallback). The previously stated 38/29 named no ordered chain,
Expand Down
2 changes: 1 addition & 1 deletion docs/adr/0022-daemon-platform-runtime-coupling.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ or owning issue. #2278 audited all four concerns at `27a97ee619`.
4. **The entry-to-platform hop trace was re-run with hop roles**
(policy / orchestration / translation / adapter / pass-through + terminal) and a deletion
test per pass-through/translation hop. The updated artifact is
[`0019-end-state-hop-trace.md`](0019-end-state-hop-trace.md): 41 hops for `press`/Android and
[`0023-end-state-hop-trace.md`](0023-end-state-hop-trace.md): 41 hops for `press`/Android and
47/49 per arm for the now dual-arm `snapshot`/iOS route (shared 30 + AX bridge 17 / runner
fallback 19). The deletion test proves a single distinct removable hop
(`commands/runtime-types.ts`); the request-spine guards (auth comparison, cancellation gate,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ADR-0019 end-state: entry-to-platform hop trace
# ADR-0023: end-state entry-to-platform hop trace

Backs the "Entry-to-platform hop count" paragraph in
[0019-request-bound-platform-runtime.md](./0019-request-bound-platform-runtime.md#end-state-proposed-2026-09-02-maintainer-decision-pending).
Expand Down
1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
| [0020 Composable Recorded Fragments (Proposed)](0020-composable-recorded-fragments.md) | lifecycle-free recorded fragment capture/composition, entry guards, fragment-local addresses/digests, staleness, and native `.ad`/Maestro composition |
| [0021 Host — Simlock-Backed Managed Device Allocation and the Host Supervisor](0021-host-simlock-managed-device-allocation.md) | local-first Simlock-managed execution, Host identity/admin boundaries, shape allocation, durable managed-device lease mapping, lifecycle ownership, and supervised maintenance |
| [0022 Daemon — Platform Runtime Coupling Audit and Ownership Ratchets](0022-daemon-platform-runtime-coupling.md) | daemon imports of root `platform-runtime-*` modules, the R76 edge classification inventory, R75 session-authority ratchet, entry-to-platform hop routes and roles |
| [0023 End-State Entry-to-Platform Hop Trace](0023-end-state-hop-trace.md) | the hop counting definition, the ordered `press`/Android and dual-arm `snapshot`/iOS chains, per-hop roles, and the deletion test behind the numbers ADR 0019 and ADR 0022 quote |

ADRs record *why*; the registries and gates they describe are the living source of truth — when
prose and a registry disagree, the registry wins and the ADR needs a follow-up.
Expand Down
45 changes: 45 additions & 0 deletions scripts/__tests__/agent-guidance-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ const BYTE_BUDGETS = {
const FOCUSED_DOC_BUDGET = 10_000;
const AGENT_DOCS_TOTAL_BUDGET = 40_000;

type PackageManifest = {
name: string;
exports?: Record<string, unknown>;
};

async function read(relativePath: string): Promise<string> {
return readFile(path.join(ROOT, relativePath), 'utf8');
}
Expand Down Expand Up @@ -56,6 +61,46 @@ test('CONTEXT.md remains a glossary rather than an architecture or workflow docu
assert.doesNotMatch(content, /(?:^|\s)(?:docs|packages|scripts|src|test)\//);
});

test('AGENTS.md routes each shared primitive to a package that publishes it', async () => {
const content = await read('AGENTS.md');
const specifiers = [
...new Set(
[...content.matchAll(/@agent-device\/[a-z0-9-]+(?:\/[a-z0-9-]+)*/g)].map((match) => match[0]),
),
];
assert.ok(specifiers.length > 0, 'AGENTS.md must route shared primitives by workspace specifier');

const published = new Map<string, Set<string>>();
for (const directory of await readdir(path.join(ROOT, 'packages'))) {
const manifest = JSON.parse(
await read(path.join('packages', directory, 'package.json')),
) as PackageManifest;
published.set(manifest.name, new Set(Object.keys(manifest.exports ?? {})));
}

for (const specifier of specifiers) {
const [scope = '', name = '', ...segments] = specifier.split('/');
const packageName = `${scope}/${name}`;
const subpaths = published.get(packageName);
assert.ok(
subpaths,
`${specifier}: AGENTS.md names a workspace package that packages/ does not publish`,
);
if (segments.length === 0) {
assert.ok(
subpaths.has('.'),
`${specifier}: AGENTS.md imports a package root ${packageName} does not export`,
);
continue;
}
const subpath = `./${segments.join('/')}`;
assert.ok(
subpaths.has(subpath),
`${specifier}: AGENTS.md names a subpath ${packageName} does not export`,
);
}
});

test('the AGENTS.md task router points only at files that exist', async () => {
const content = await read('AGENTS.md');
const table = content.match(/\| When the task involves \| Read \|([\s\S]*?)\n\n/)?.[1];
Expand Down
5 changes: 4 additions & 1 deletion website/docs/docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ One-off `npx` usage is fine for humans and scripts that intentionally fetch from

## Requirements

- Node.js 22+
- Node.js 22.12 or newer
- Node.js 24 or newer for web automation, which hard-fails below it. The rest of the CLI keeps the
22.12 floor, so check `node --version` in the shell that runs `agent-device web setup` and
`agent-device doctor` before trusting a web result.
- Xcode for iOS simulator/device automation (`simctl` + `devicectl`)
- Android SDK / ADB for Android
- HarmonyOS Command Line Tools for HarmonyOS (`hdc` available through `HDC_SDK_PATH`, `DEVECO_SDK_HOME`, or `HARMONYOS_COMMAND_LINE_TOOLS`)
Expand Down
Loading