Skip to content

feat(hosts): add Pi coding agent host adapter - #25

Open
NickyLam wants to merge 1 commit into
QoderAI:mainfrom
NickyLam:feat/pi-host-adapter
Open

feat(hosts): add Pi coding agent host adapter#25
NickyLam wants to merge 1 commit into
QoderAI:mainfrom
NickyLam:feat/pi-host-adapter

Conversation

@NickyLam

Copy link
Copy Markdown

Summary

Pi (pi.dev, @earendil-works/pi-coding-agent) can now run /better-harness as a first-class host: pi install <repo> discovers the skill and a /better-harness prompt template, and reviews on Pi gain real configured-asset and session evidence instead of unobserved lanes.

Why

  • Issue/Story: none — this follows the contribution table's invitation to "document and validate evidence support for another coding-agent host", using the recently added Qwen Code host as the structural template.
  • User or maintainer outcome: Pi users get durable HTML + Markdown reports backed by their own session transcripts and pi-package/skill/prompt inventory; previously Better Harness had no Pi support at all.

Traceability and Scope

  • Spec/ADR, if applicable: docs/adapters/README.md host-boundary contract (host differences enter only the matrix, configured-asset providers, session adapters, and output modes).
  • Acceptance criteria addressed: Pi row in the adapter matrix; --platform pi accepted across session-analysis, evidence-bundle, asset-baseline/integrity, task-loop, report-run, and agent-lint; pi install/pi -e discovery works from the repository root.
  • Canonical owners changed: scripts/agent-customize/providers/pi.mjs and scripts/session-analysis/platforms/pi.mjs (new), platform registration lists across scripts/, package.json (pi manifest, prompts/ packaging), prompts/better-harness.md, references/agent-customize/platforms/pi.md, adapter-matrix docs (en/zh), READMEs, CHANGELOG.
  • Explicit non-goals: no native MCP inventory for Pi (Pi has none; MCP arrives via extensions and stays extension-bound), no pi-package glob-filter/enable-state inventory, no docs/adapters/pi.md split (no split trigger met), no change to the Qoder runtime bundle contents.

Change Type

  • Feature

Test and Review Evidence

Check Result
npm test 874/874 pass (baseline 867 + 7 new Pi tests)
npm run pack:verify pass — npm 313 entries incl. package/prompts/better-harness.md; runtime zip 338 entries with prompts/ correctly excluded
node scripts/session-analysis.mjs sources --platform pi --workspace /private/tmp (real local Pi data) 4 workspace-matching sessions discovered; cross-workspace transcripts rejected
node scripts/session-analysis.mjs facts --platform pi ... session-core-facts with 2 candidates; no session-id or home-path leakage in output
better-harness agent-customize inventory --provider pi (real ~/.pi/agent) 12 pi-package plugins across npm/git/extension-dir sources, 56 user skills, prompt commands, AGENTS.md rules
better-harness harness evidence-bundle --platform pi --workspace <repo> status: complete; sessionEvidence/projectHarness/agentCustomize + lead all available
Pi's own DefaultPackageManager.resolveExtensionSources(<repo>) in an isolated agent dir resolves exactly 1 skill (better-harness) and 1 prompt template (better-harness.md) from the pi manifest

Manual or visual evidence: session-format fixtures were derived from real Pi v3 JSONL transcripts and pi 0.83.0 source (session-manager.js slug rule, config.js env overrides), not from documentation alone.

Risk and Recovery

  • Compatibility and cross-platform impact: existing hosts unchanged (all pre-existing tests pass without behavioral edits; only usage strings, provider lists, and two frozen CLI-contract hashes moved). Windows session-dir slugs (\ and : replacement) are covered by unit tests.
  • Package, plugin, schema, or generated-file impact: npm package adds the pi manifest key, pi-package keyword, and prompts/; verify-pack enforces the new required entry and forbids prompts/ from the Qoder runtime bundle. No schema changes.
  • Rollback or recovery path: revert this single commit; no migrations or generated state.
  • Residual risk or unverified boundary: a full end-to-end /better-harness report run inside an interactive Pi session (model-driven) was not exercised; discovery, evidence collection, and bundle assembly were verified directly. Pi package manifest glob filters and per-resource enable state are declared unsupported rather than inventoried.

AI Involvement

  • Level: Generated
  • Human review and validation: contributor reviewed the full diff and ran the complete validation matrix above (test suite, pack verification, and smoke runs against real local Pi data).

Checklist

  • I followed AGENTS.md, CONTRIBUTING.md, and the relevant canonical-owner guidance.
  • The change is focused and does not include unrelated local or generated state.
  • Tests and documentation match the behavior actually delivered.
  • Markdown links were checked when documentation moved or changed.
  • Cross-platform behavior was considered for Windows, macOS, and Linux.
  • Package/runtime verification was run when shipped files or dependencies changed.
  • User-facing or compatibility changes are recorded in CHANGELOG.md.
  • I have the right to contribute this work under the repository's MIT License.

Add Pi (pi.dev / @earendil-works/pi-coding-agent) as an
analysis-capable source-local host, following the Qwen Code host
template:

- Distribution shell: `pi` manifest in package.json plus a
  /better-harness prompt template, so `pi install <repo>` discovers
  the canonical skills/ root and registers the slash command; add the
  pi-package keyword and ship prompts/ in the npm package while
  keeping it out of the Qoder runtime bundle.
- Configured assets: scripts/agent-customize/providers/pi.mjs
  inventories settings-declared pi packages (npm/git/local),
  extensions, skills (including shared .agents/skills), prompt
  templates, and AGENTS.md context rules for user and project scopes.
- Session evidence: scripts/session-analysis/platforms/pi.mjs reads
  workspace-matching JSONL v3 transcripts under
  ~/.pi/agent/sessions/--<cwd-slug>--/, honors PI_CODING_AGENT_DIR and
  PI_CODING_AGENT_SESSION_DIR, verifies the session-header cwd, and
  normalizes user/assistant/toolResult messages, toolCall blocks, and
  usage into provider-labelled events.
- Register the pi platform across session-analysis, evidence-bundle,
  asset-baseline/integrity, task-loop, report-run, and agent-lint
  surfaces with --pi-home threading.
- Sync the host adapter matrix, site docs (en/zh), references
  (platforms/pi.md, routing, sessions diagnostics), and READMEs; add
  provider, inventory, baseline, and evidence-bundle tests with
  fixtures matching the real Pi v3 session format.

Validated with npm run check (874 tests, pack verification) and
against real local Pi data: session discovery, agent-customize
inventory, and a complete pi evidence bundle; Pi's own package
resolver discovers the skill and prompt template from this repo.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class support for the Pi coding-agent host (pi.dev, @earendil-works/pi-coding-agent) by introducing a new Pi session-analysis adapter, a Pi agent-customize inventory provider, and the pi-package discovery surfaces (manifest + /better-harness prompt template). This aligns with the repo’s host-boundary approach where host differences live in the adapter matrix, configured-asset providers, session adapters, and output modes.

Changes:

  • Add Pi session evidence adapter (--platform pi) with JSONL v3 parsing and workspace scoping.
  • Add Pi configured-asset inventory provider and wire pi into harness/evidence-bundle/task-loop/report CLI surfaces.
  • Ship a pi manifest + prompts/ template in the npm package; update docs/README/changelog and add tests.

Reviewed changes

Copilot reviewed 49 out of 49 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/session-analysis-providers.test.mjs Adds Pi analyzer coverage and Pi transcript fixtures.
test/scripts-refactor-contract.test.mjs Updates frozen CLI output hashes after new platform.
test/plugin-manifests.test.mjs Verifies package.json.pi and prompts/ packaging rules.
test/fixtures/scripts-refactor-contract/session-help.txt Updates help fixture to include pi.
test/fixtures/scripts-refactor-contract/root-help.txt Updates root help fixture to mention Pi.
test/coding-agent-platform-notes.test.mjs Ensures sessions diagnostics notes include Pi paths.
test/better-harness-evidence-bundle.test.mjs Adds Pi agentCustomize lane routing test.
test/agent-customize.test.mjs Adds Pi inventory/provider tests and fixtures.
test/agent-customize-architecture.test.mjs Updates architecture doc expectations for “six metadata roots”.
test/agent-asset-baseline.test.mjs Adds Pi asset baseline fixture test.
scripts/session-analysis/usage-summary.mjs Extends --platform usage to include pi.
scripts/session-analysis/selection-profile.mjs Extends --platform usage to include pi.
scripts/session-analysis/platforms/pi.mjs Implements Pi session discovery + normalization (new).
scripts/session-analysis/lifecycle-demand-signals.mjs Allows pi in host-safe normalization.
scripts/session-analysis/analyzer.mjs Wires Pi platform loader + help strings.
scripts/session-analysis.mjs Wires Pi platform loader + help strings (shim).
scripts/npm-package/verify-pack.mjs Requires prompt template in package and forbids it in runtime bundle.
scripts/harness-analysis/task-loop-source.mjs Accepts pi platform; threads pi-home through evidence collection.
scripts/harness-analysis/task-loop-report.mjs Recognizes pi in platform selection.
scripts/harness-analysis/report-run.mjs Accepts pi and --pi-home for report runs.
scripts/harness-analysis/report-quality.mjs Adds Pi to session-scope detection patterns.
scripts/harness-analysis/evidence-bundle/contract.mjs Adds pi to allowed providers.
scripts/harness-analysis/evidence-bundle/cli.mjs Accepts --pi-home and pi platform.
scripts/harness-analysis/evidence-bundle/agent-customize.mjs Enables Pi for agentCustomize lane.
scripts/coding-agent-practices/inventory.mjs Accepts pi and includes piHome in scope.
scripts/coding-agent-practices/asset-integrity.mjs Accepts pi provider.
scripts/coding-agent-practices/asset-baseline.mjs Accepts pi provider.
scripts/better-harness-cli/registry.mjs Updates session-analysis command summary to include Pi.
scripts/agent-lint/cli.mjs Allows `--provider ...
scripts/agent-customize/providers/pi.mjs Implements Pi configured-asset inventory (new).
scripts/agent-customize/providers/index.mjs Registers Pi provider collector.
scripts/agent-customize/cli.mjs Threads --pi-home through CLI.
references/session-evidence/sessions-diagnostics.md Adds Pi platform notes for session evidence diagnostics.
references/agent-customize/routing.md Adds Pi asset routing guidance.
references/agent-customize/README.md Adds Pi platform notes link.
references/agent-customize/platforms/pi.md Adds Pi operating-practice reference (new).
README.zh-CN.md Documents Pi installation and report usage (zh-CN).
README.md Documents Pi installation and report usage (en).
prompts/better-harness.md Adds /better-harness prompt template (new).
package.json Adds pi manifest + pi-package keyword + ships prompts/.
docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/hosts/adapter-matrix.md Adds Pi to host adapter matrix (zh-Hans).
docs/glossary.md Updates session-analysis + host shell glossary entries for Pi.
docs/docs/hosts/adapter-matrix.md Adds Pi to host adapter matrix (en docs site).
docs/concepts.md Updates session-evidence concept to include Pi.
docs/community.md Updates “host shell and packaging” to include Pi manifest.
docs/ARCHITECTURE.md Updates “five” → “six” plugin metadata roots wording.
docs/adrs/directory-structure.md Updates platform adapter list and packaging roots count.
docs/adapters/README.md Adds Pi row and discovery/evidence notes.
CHANGELOG.md Records Pi host support under Unreleased.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +303 to +321
async discoverSourceRoots(scope) {
const roots = [
{
id: "pi-sessions",
kind: "pi-session-jsonl",
role: "session-transcript",
path: path.join(scope.sessionsDir, scope._workspaceDirVariants.exact),
paths: [scope.sessionsDir],
optional: false,
enabled: true,
workspaceScoped: true,
coverage: "primary",
},
];
return Promise.all(roots.map(async (root) => ({
...root,
exists: await pathExists(root.path) || await pathExists(root.paths[0]),
})));
}
Comment thread prompts/better-harness.md

User request:

${@:-review this project's AI coding workflow and generate a report}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified against an isolated install of @earendil-works/pi-coding-agent@0.83.0: Pi's prompt-templates API and runtime substituteArgs() explicitly support ${@:-default}. The no-argument case expanded to the fallback, and ["one", "two"] expanded to one two.

So line 19 is valid and should not be changed just for this concern. I suggest documenting the default-value form in the Pi platform notes and adding an expansion smoke test so the supported syntax is visible in-repo.

@phodal phodal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran an isolated native smoke with @earendil-works/pi-coding-agent@0.83.0 and compared Pi's own resolver/session behavior with this adapter.

What already works:

  • pi install / pi list accepts this package.
  • Pi's DefaultPackageManager resolves exactly the canonical better-harness Skill and prompt from the package manifest.
  • npm run check passes locally: 874/874 tests plus pack verification.

There are still native-contract blockers in the inline comments below. In addition, please update the branch before merge:

  1. Rebase onto current main, which now includes PR #22 and PR #23. At this head, git merge-tree reports 37 content conflicts. Resolve host registries as a union so Copilot support is retained while Pi is added.
  2. Add a dated Pi host spec under docs/specs/ with stable acceptance IDs, and link the new Coding Agent contribution guide. The guide links PR #6 and PR #22 as reviewed examples.
  3. Amend the commit with the required single Co-authored-by line.
  4. Re-run CI after updating the head. The current run is action_required with no jobs, so it is not green CI.

One environment note: the local suite ran under Node 26, outside the repository's declared Node range. The passing local suite is useful evidence but should not replace CI on a supported runtime.

options.home ?? options.piHome ?? options["pi-home"] ?? process.env.PI_CODING_AGENT_DIR ?? "~/.pi/agent",
));
const sessionsDir = path.resolve(expandHome(
options.sessionsDir ?? options["sessions-dir"] ?? process.env.PI_CODING_AGENT_SESSION_DIR ?? path.join(home, "sessions"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking native-contract mismatch: Pi 0.83 treats --session-dir, PI_CODING_AGENT_SESSION_DIR, and settings.json sessionDir as the exact directory containing JSONL files. It does not treat a custom directory as a root containing --<cwd-slug>-- children.

I reproduced this with Pi's SessionManager.create(workspace, customDir): native SessionManager.list(workspace, customDir) found 1 session, while this adapter found 0. SettingsManager.getSessionDir() also returned the configured directory, but resolveScope() fell back to <piHome>/sessions.

Please distinguish the default cwd-keyed tree from a custom flat session directory, honor CLI > env > settings > default, qualify custom-directory files by the session-header cwd, and add positive/foreign-workspace tests for env and settings overrides. This should also address the existing source-root warning thread, because a parent directory alone is not proof of a workspace evidence root.

installSource: scope,
installMatch: `pi-settings-${record.sourceKind}`,
installType: record.sourceKind,
enabled: true,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking effective-state issue: object-form package settings are reduced to source, then every installed package and its resources are reported as enabled: true.

With packages: [{ source, autoload: false, skills: [], prompts: [] }], Pi's native DefaultPackageManager resolves zero package Skills and prompts, while this provider still reports both better-harness resources as enabled. Declaring filters unsupported does not make it safe to publish disabled resources as effective configured assets.

Please apply Pi's manifest/settings filters and negative selectors, or fail closed without publishing those child resources as enabled. Add fixtures for autoload: false, explicit allowlists, and negative overrides.

function piUserHomeBase(piHome) {
// The default agent dir is <home>/.pi/agent; derive the owning home so the
// shared ~/.agents/skills surface stays bound to the inspected pi home.
return path.dirname(path.dirname(piHome));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PI_CODING_AGENT_DIR relocates Pi's agent/config directory, but native Pi still discovers the Agent Skills standard directory from the real user home at ~/.agents/skills. Deriving the user home by taking two parents of an arbitrary piHome changes that contract.

In an isolated PI_CODING_AGENT_DIR smoke, Pi's resolver still found the real ~/.agents/skills, while this provider missed them. Please model piHome and user home separately (or use os.homedir() for the native global surface), preserve the includeUserHome privacy boundary, and add a custom-agent-dir fixture.

cacheCreationInputTokens: usage.cacheWrite ?? usage.cacheCreationInputTokens,
};
return Object.values(fields).some((value) => value !== undefined)
? Object.fromEntries(Object.entries(fields).map(([key, value]) => [key, Number.isFinite(Number(value)) ? Number(value) : 0]))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing usage fields should remain unobserved, not be converted to zero. Once any one usage field exists, this mapping turns every absent or malformed sibling field into 0.

Current main and the PR #22 evidence contract keep partial usage explicit. Please emit only finite fields actually observed, preserve missing input/cache fields as absent, and add partial plus malformed usage fixtures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants