Skip to content

v3.1.0 — DeepSeek Harness target, hook documentation, Amp watch-pr lifecycle

Latest

Choose a tag to compare

@oliver-kriska oliver-kriska released this 27 Aug 14:31
428674d

Warning

Already on v3.0.x? A plain /plugin update is all you need — skip this box.

Coming from v2.x, do not run claude plugin update on its own. v3
introduced two compatibility plugins (ecto, lv) that v2 never declared,
and claude plugin update does not install dependencies a new version newly
declares. The plugin then fails to load entirely — you lose all 36 /phx:*
commands, not just /ecto:* and /lv:*. Install the two first, in this
order:

claude plugin marketplace update oliver-kriska
claude plugin install ecto@oliver-kriska
claude plugin install lv@oliver-kriska
claude plugin update elixir-phoenix@oliver-kriska

Already updated in the wrong order and seeing ✘ failed to load? Nothing is
lost — claude plugin install ecto@oliver-kriska then
claude plugin install lv@oliver-kriska recovers it (one dependency per
invocation).

A fifth runtime target (DeepSeek Harness), the first user-facing hook
documentation, and a native Amp phx-watch-pr lifecycle.

Added

  • DeepSeek Harness (dsh) target (#139) — a fifth generated runtime target
    at targets/dsh/, projecting all 51 canonical skills with their complete
    resource subtrees. dsh's dsh-skill-filesystem provider scans
    .agents/skills and friends for single-level <name>/SKILL.md bundles, and
    its pre-step boundary injects the full body for a whitespace-bounded
    /phx-* token, so the plugin's command surface survives intact. dsh also
    reads CLAUDE.md natively, so /phx:init output needs no porting. Adds
    scripts/port_lib/dsh.py, scripts/build_dsh_skills.py, twelve tests in
    scripts/tests/test_dsh.py, make dsh-skills{,-sync,-validate} wired into
    generated-skills-sync and ci, an optional make dsh-runtime-smoke that
    verifies discovery over dsh's loopback /api RPC bridge (session.create then
    skill.list, no API key needed), a golden snapshot entry, docs/dsh.md, and
    a dsh column in docs/runtime-support.md. Two dsh-specific build gates:
    descriptions are capped at the 500-char catalogDescriptionMaxLength (dsh
    truncates silently past it) and nested SKILL.md files are rejected (dsh
    discovery is deliberately one level deep). Skills-only by design — dsh has no
    markdown agent registry, and its Claude Code hook bridge covers 7 of 30 events
    while dropping if: gating, so neither the 26 agents nor the 30 hooks ship.
    Tested against dsh 0.1.1-rc.2, a developer preview.

  • Hook documentation — the 23 hooks across 10 lifecycle events had no
    user-facing docs; the reasoning lived only in script header comments and a
    terse contributor checklist. Adds HOOKS.md at the repo root (what fires
    when, a lifecycle diagram, the full hook table, escape hatches),
    plugins/elixir-phoenix/hooks/README.md (per-event output-channel table and
    the shared conventions: mix.exs gating, the fail-open contract, if
    conditions, blame-aware scanning), and six per-group deep dives under
    plugins/elixir-phoenix/hooks/docs/ — safety gates, code quality, failure
    recovery, context injection, session lifecycle, workflow state. Each records
    the incident or measurement the hook came from (issue #55 cross-project
    bleed, issue #61 --force-with-lease, issue #38 progress.md cross-writes,
    the ~0% CLAUDE.md routing finding). CLAUDE.md now requires these docs to be
    updated in the same commit as any hook change.

  • Amp-native phx-watch-pr lifecycle — the deterministic Amp target now
    includes a focused Plugin API runtime that acquires an Orb keep-alive lease,
    persists watch state across reloads, filters deployment-like checks out of
    readiness, detects unresolved review threads and required CI failures, and
    serializes --fix events back into the same worker thread. Defaults are a
    60-second poll, 15-minute activity-based quiet period, and 2-hour hard
    active-watch cap; head pushes, required-check transitions, reviews, and
    comments restart quiet so delayed reviews cannot be hidden by an early green
    snapshot without waking inference for routine progress. Deployment-only
    transitions remain status-visible but silent. Every terminal path releases
    the lease, and the plugin never blindly reruns shared CI, merges, or deploys.
    An optional durable Amp webhook can reactivate a completed watch after the
    Orb pauses only when the event identifies the exact watched PR or head SHA;
    repository webhook configuration remains an explicit external administrator
    action.

  • README links phxagents.dev above the fold — a docs badge, a one-line
    Docs block pointing at /install/, /compatibility/, /iron-laws/ and
    /catalog/, and a per-runtime install-guide link in each of the four
    "Using Amp/Codex/Pi/OpenCode?" callouts. The README had zero
    phxagents.dev mentions across 1,056 lines while being the project's
    higher-traffic discovery surface: over 08/02-08/15, Google sent 56 unique
    visitors to the repo versus 14 from the docs site, so everyone arriving from
    search read the whole README and never learned the docs site exists. The
    repo's About → Website field was already set.

  • Deterministic Amp workflow plugin — the generated Amp target now includes
    40 workflow palette commands, five read-only domain specialists, bounded
    parallel review and investigation, a persistent classified edit lock, and a
    bounded phx-full verification gate. The standalone distribution promotes a
    validated stable branch for direct GitHub installation.

Changed

  • route-intent.sh timeout raised 10s → 30s — the UserPromptSubmit
    intent-routing hook had the tightest budget of any hook in the plugin despite
    sitting on the latency path of every prompt. It normally finishes in well
    under 100ms (it truncates the prompt to 4000 chars before scanning), but a
    timeout drops the routing hint silently, so the extra headroom costs nothing
    on the common path and avoids losing suggestions on a slow first run. The
    hook already exits 0 on every path — a UserPromptSubmit hook must never
    exit 2, which would erase the user's prompt.

  • Release bodies now carry a docs-site footer — the release contributor
    skill gained an Iron Law and a printf step that appends
    <https://phxagents.dev> to the extracted CHANGELOG release notes. A release
    body is read at the moment someone decides whether to install, and releases
    are this project's one promotion lever with a measured effect: v3.0.1 drove
    unique cloners from 51 to 120 in a single day (2.4x), decaying to baseline
    over about four days.

  • Amp installation profiles and scope names now match current Amp — docs
    distinguish hosted-native from paired-full behavior, use native skill: invoke for deterministic hosted skill loading, and separate machine-local
    --global installs from personal/workspace hosted repositories. The public
    standalone repository, generated target, gated stable branch, paired local
    install, and GitHub/curl fallback remain supported.

  • deep-bug-investigator synthesizes on opus, its four tracks run on sonnet
    (thanks @BugsBunny338, #133) — the agent coordinates four parallel
    investigation tracks and then reconciles their often-conflicting evidence.
    Cross-track synthesis is where the stronger model earns its cost, and
    hard-to-reproduce bugs are where a weak synthesis is most expensive. The
    frontmatter bump alone would have been the wrong fix: the tracks spawn as
    bare general-purpose subagents, which default to model: inherit and so
    resolve to the spawning parent's model — opus on the orchestrator would
    have silently promoted the whole fan-out to five opus contexts. The tracks
    are now pinned to model: "sonnet" explicitly, keeping fan-out cost where it
    was: sonnet gathers evidence, opus synthesizes. effort: medium is
    unchanged; the eval allowlists opus for orchestrators, so no symmetry fix is
    owed.

  • workflow-orchestrator pins its COMPOUNDING spawn to sonnet — same
    inheritance leak as above, found while reviewing #133. The orchestrator runs
    on opus and spawned an unpinned general-purpose subagent to write solution
    docs, so that mechanical phase was silently billed at opus. Named phx:*
    subagents were never affected — their own frontmatter wins — so
    parallel-reviewer and planning-orchestrator needed no change.

  • The release contributor skill hoists upgrade warnings to the top of the
    release body
    — a new Iron Law and template: when a release needs anything
    beyond /plugin update, the body opens with a > [!WARNING] block carrying
    the exact commands, and states the blast radius in what the user loses rather
    than in mechanism. v3.0.0 documented its staged upgrade correctly but placed
    it at roughly line 145 of a long changelog dump, phrased as "a temporary
    missing-dependency state" — and users upgraded into a broken install anyway
    (#135). A correct instruction nobody reaches is indistinguishable from a
    missing one.

  • CLAUDE.md model-tier rules describe the actual split — the guidance said
    "opus for primary workflow orchestrators, sonnet for secondary orchestrators
    (investigation, tracing)", which stopped matching the plugin once
    planning-orchestrator moved to sonnet and deep-bug-investigator moved to
    opus. The rule is now stated in terms of what earns opus (synthesis across
    parallel workers) and names the four agents on each side, plus the
    general-purpose pinning requirement that follows from it.

Fixed

  • Canonical skills told every runtime to run Claude Code's /mcp (#141) —
    tidewave-integration/SKILL.md (Iron Law 3) and examples/SKILL.md both used
    /mcp to check MCP availability, and shipped byte-identical to all five
    generated targets, where that command does not exist. Iron Law 3 now reads
    "Call Tidewave only when matching mcp__tidewave__* tools are present" — a
    check that works on every runtime — and the examples fence drops the probe
    for a # Requires connected mcp__tidewave__* tools note, switching from a bash
    fence to a text one since its contents are tool invocations rather than
    shell. The one remaining mention stays, already qualified with "in Claude
    Code". Found while reviewing #140; fixing it in one target would have broken
    the test asserting the two Agent Skills projections differ only by the
    runtime name.

  • The phx-watch-pr harness test was one second from red — it ran with a
    60-second subprocess timeout and takes ~59 seconds of wall time for ~3 seconds
    of CPU: the harness drives a fake clock with real 80ms flushes, and advance()
    performs up to 21 of them across 23 calls. Observed locally at 58.9s, 60.4s,
    and 73.9s on consecutive runs, so it passes or fails on runner load alone —
    and it is a required check, meaning it would have started blocking unrelated
    PRs. Raised to 240s; the harness itself is unchanged, since shortening the
    flush would trade a timeout flake for a race.

  • The phx-watch-pr install command could never have worked — README and
    docs/amp.md told users to run amp plugins add against a
    raw.githubusercontent.com URL. Amp 0.0.1787045288 rejects that with
    For now, only https://ampcode.com/@amp/plugins/*.ts ... URLs are allowed and
    writes nothing. The same docs/amp.md already said, 390 lines further down,
    that "Amp currently restricts amp plugins add ... to Amp-hosted plugins" —
    the file contradicted itself, and the install instruction was the wrong half.
    Both call sites now use the atomic curl + mv pattern already documented
    for elixir-phoenix.ts, pointing at the standalone repository's stable
    branch. The update section covers both plugins instead of only the workflow
    one.

  • Upgrading from v2.x no longer lands users in a dead install (reported by
    @barquesurlocean, #135) — v3.0.0 renamed the plugin manifest to phx (which
    is what makes /phx:* correct; pre-v3 versions namespaced their commands as
    /elixir-phoenix:* while /phx:init wrote /phx:* into CLAUDE.md) and in
    the same commit introduced the ecto and lv compatibility plugins as
    manifest dependencies. Adding a dependency turns out to be a breaking
    change for already-installed users: claude plugin update does not
    install dependencies a new version newly declares, and a missing dependency
    is a hard load failure, so the obvious /plugin update leaves the plugin at
    ✘ failed to load with all 36 /phx:* commands gone — taken down by the 3
    compatibility commands. Verified on Claude Code 2.1.234, so this is not the
    2.1.76–2.1.109 version band recorded during #130; it affects every v2 user on
    every Claude Code version. Nothing self-heals either, because auto-update is
    off by default for non-Anthropic marketplaces. The README's staged upgrade
    block was already correct but described the failure as "a missing-dependency
    state"; it now leads with a warning, states the blast radius in commands
    lost, declares the 2.1.110 version floor, adds a recovery path for anyone who
    already updated in the wrong order, and explains the /phx: vs
    /elixir-phoenix: prefix history. Note during recovery that
    claude plugin install elixir-phoenix@oliver-kriska resolves only one
    missing dependency per invocation.

  • make validate covers every plugin manifest — the target validated
    plugins/elixir-phoenix and the marketplace only, so plugins/ecto,
    plugins/lv, and plugins/catchup could ship a schema violation that CI
    never saw. This is exactly how displayName reached users: it was present in
    all four Claude-facing manifests while the gate looked at one of them. All
    five manifests are validated now.

  • Amp wrapper skill resolution follows supported local precedence — the
    generated plugin now checks machine-local skill roots before workspace roots
    and searches .agents/skills and .claude/skills through the parent
    directories exposed from workspaceRoot. Docs explicitly call out sources
    the Plugin API cannot resolve, including hosted repositories, built-ins,
    plugin caches, custom amp.skills.path, and nested invocation roots that are
    not exposed to plugins.

  • displayName removed from all Claude Code manifests (reported by
    @ndrean, #130) — the field was introduced alongside the v3 plugin split and
    reported as an install blocker one day later. It is undocumented: it appears
    nowhere in the plugin manifest schema, whose metadata fields are version,
    description, author, homepage, repository, license, and keywords.
    It is also inert — claude plugin list renders the plugin name, never
    displayName — and Anthropic's own marketplace uses it in 3 of 285 entries,
    always in marketplace.json and never in a plugin.json, which is exactly
    where this repo had it. catchup had already been shipping without it. A
    clean install from GitHub could not be reproduced as broken on 2.1.227, so
    the original failure was likely specific to the Claude Code range current in
    late July; the field is gone regardless, since nothing depended on it. The
    Codex manifests (targets/codex/.codex-plugin/plugin.json,
    .agents/plugins/marketplace.json) keep theirs — different runtime,
    different schema, where it is nested under interface.


Docs, install guides, and the runtime compatibility matrix: https://phxagents.dev