Skip to content

feat(amp): add deterministic native workflows - #132

Merged
oliver-kriska merged 4 commits into
mainfrom
feat/amp-native-workflows
Aug 18, 2026
Merged

feat(amp): add deterministic native workflows#132
oliver-kriska merged 4 commits into
mainfrom
feat/amp-native-workflows

Conversation

@oliver-kriska

@oliver-kriska oliver-kriska commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

Refresh the canonical Amp integration on current main and make its workflow behavior deterministic where the supported Plugin API allows. The generated target includes all 51 Agent Skills, 40 paired-local workflow wrappers, five native controls, five read-only specialists, bounded parallel analysis, and lifecycle safety controls.

This branch was rebased from the original #132 onto main at 3f0f117; generated artifacts were regenerated from canonical source rather than conflict-merged. The installable artifacts remain owned here and will be projected from the reviewed commit into the separately gated amp-elixir-phoenix distribution PR.

What changes

  • Generate 40 workflow palette wrappers and five native controls alongside all 51 Agent Skills.
  • Project the canonical Elixir, Ecto, LiveView, security, and testing reviewers into lower-cost child agents restricted to Read and finder.
  • Add bounded parallel review/investigation, a persistent classified edit lock, and a bounded wrapper-activated phx-full verification gate.
  • Align local wrapper resolution with Amp's supported precedence: machine-local roots first, then .agents/skills and .claude/skills from exposed workspaceRoot through its parents, then the legacy home fallback.
  • Skip missing, unreadable, and non-file candidates so invalid higher-precedence entries cannot mask a valid lower source.
  • Make the Bun plugin behavior harness a required CI check rather than an optional local skip.
  • Compact generated metadata and share the repeated specialist contract in the output so the 95,269-byte plugin remains below Amp's hosted process-argument transport boundary while reconstructing the same enforced instructions at runtime.
  • Document native skill: invoke, hosted-native versus paired-full profiles, machine-local versus personal/workspace hosted scope, independent skills/plugin publication, and skills-first rollout ordering.
  • Preserve the standalone repository, generated target, gated mutable stable, paired local install, and GitHub/curl compatibility paths.

Explicit Plugin API boundary

Native skill: invoke uses Amp's effective resolver and supports local, built-in, personal hosted, and workspace hosted skills. The current Plugin API does not expose skill resolution/invocation or Amp's original nested invocation directory, so filesystem wrappers cannot correctly inject hosted-only, built-in, plugin-cache, custom-path, or unexposed nested skill bodies.

Consequently:

  • hosted-native supports native skill invocation, specialists, parallel commands, and edit lock;
  • paired-full supports those features plus all 40 local wrappers;
  • only paired phx: full arms the plugin verification gate; native hosted skill: invokephx-full follows skill guidance but cannot activate that wrapper hook.

The implementation documents this boundary instead of scanning undocumented Amp caches or claiming unsupported hosted wrapper behavior.

Safety and distribution

Specialists cannot edit, run shell commands, or recursively create agents. Edit-lock paths resolve symlinks and fail closed on malformed, unreadable, or workspace-escaping state. Verification rejects piped, chained, neutralized, pre-edit, unrelated-PID, and nonzero-exit checks.

The generated plugin deliberately retains the direct GitHub/curl fallback. Promotion to the standalone distribution and mutable stable remains separately review-gated; neither is changed by this canonical PR.

Rebase onto 874d2e4 (two Amp plugins)

main landed feat(amp): add native PR watch lifecycle while this branch was
open, which introduced a second Amp plugin on the same generator surface.
Both commits independently defined build_target(), validate_plugin(), and
the same OUTPUT_DIR, with different designs:

this branch 874d2e4
plugin elixir-phoenix.ts phx-watch-pr.ts
produced by rendered from Python copied verbatim from canonical source
why inlines projected agent bodies and skill metadata real TypeScript with no projected data

Neither style can replace the other, so build_target() now emits both.
validate_plugin() keeps main's signature and meaning; the rendered one became
validate_workflow_plugin() and PLUGIN_RELATIVE_PATH became
WORKFLOW_PLUGIN_RELATIVE_PATH, confining the rename to this branch. Generated
files were regenerated from source, never hand-merged.

The transport budget needed the full branch: after the first commit the rendered
plugin reached 98,745 bytes against its own 96,000 assert (phx-watch-pr joined
PORTABLE_WORKFLOWS, and the shared specialist contract was still inlined five
times). The third commit's compaction lands it at 95,191 bytes, 809 bytes of
headroom
.

Verification

Canonical commit: b748795 (rebased onto main at 874d2e4)

  • make ci — PASS: 243 tests (including the Bun runtime harness), Claude manifest validation, all generated-target drift/snapshot checks, and full structural eval (51 skills, 26 agents). Skillspector was not installed in the orb, so the Makefile's optional security target reported its documented skip.
  • make amp-runtime-smoke — PASS with Amp 0.0.1786436318-g8453bf (2026-08-11): 51 skills and plugin loaded in isolation without model calls.
  • Personal hosted plugin transport pilot — PASS: the exact 95,269-byte plugin loaded user-scoped with all 45 commands and both parallel tools; the interactive edit lock blocked shell execution and hosted-only wrappers failed with their documented local-install requirement.
  • make amp-target-validate — PASS: 51 skills and plugin, with regenerated golden snapshot.
  • Focused resolver/runtime suite — PASS: 31 tests under Bun 1.3.14, including machine-local precedence, parent-directory resolution, invalid-entry fallback, all wrappers, specialists, parallel partial failure, edit-lock escapes, and verification lifecycle cases.
  • Ruff, yamllint, Markdown lint, npm audit --audit-level=high, and git diff --check — PASS; npm audit found 0 vulnerabilities.

Review focus

The highest-value review areas are the documented hosted-wrapper boundary, local resolver precedence, Amp lifecycle assumptions, edit-lock enforcement, verification result classification, and generator-to-target parity.


Compound Engineering

oliver-kriska and others added 4 commits August 18, 2026 11:29
Generate a complete Amp target with explicit palette commands, read-only
specialists, bounded parallel analysis, and lifecycle guards. Keep the source
target byte-identical to the validated standalone distribution and cover the
runtime policies with model-free tests and smoke checks.

Co-authored-by: Oliver Kriska <oliver@ideax.sk>
main added a second, hand-written Amp plugin (phx-watch-pr.ts, copied
verbatim and byte-checked against its canonical source) while this branch
added a first one (elixir-phoenix.ts, rendered from Python so it can embed
projected agent bodies and skill metadata). Both landed on the same
build_target(), the same validate_plugin(), the same OUTPUT_DIR, and the
same snapshot digest.

Neither generation style can replace the other: the workflow plugin has to
be rendered because it inlines canonical content, and the watch plugin has
to be copied because it is real TypeScript with no projected data. So the
target now emits both.

- validate_plugin() keeps main's signature and meaning (watch plugin,
  byte-identity against source). The rendered one becomes
  validate_workflow_plugin(), and PLUGIN_RELATIVE_PATH becomes
  WORKFLOW_PLUGIN_RELATIVE_PATH, so main's committed API is untouched and
  the rename stays confined to the incoming branch.
- build_target() discovers specialists, copies the watch plugin, renders
  the workflow plugin, and returns skills + commands + plugins.
- The runtime smoke test now execs both plugins: session.start for
  phx-watch-pr, agent.start for elixir-phoenix.
- Docs and the runtime-support matrix describe two plugins rather than
  one, keeping both sides' capability rows.

The transport budget needed the whole branch to land: after commit 1 the
rendered plugin hit 98,745 bytes against its own 96,000 assert, because
phx-watch-pr joined PORTABLE_WORKFLOWS and the shared specialist contract
was still inlined five times. Commit 3's compaction brings it to 95,191
with 809 bytes of headroom.
@oliver-kriska
oliver-kriska force-pushed the feat/amp-native-workflows branch from 3ea78b0 to b748795 Compare August 18, 2026 09:42
@oliver-kriska
oliver-kriska merged commit 7c613bd into main Aug 18, 2026
6 checks passed
@oliver-kriska
oliver-kriska deleted the feat/amp-native-workflows branch August 18, 2026 09:44
oliver-kriska added a commit that referenced this pull request Aug 18, 2026
README and docs/amp.md told users to install the watcher with `amp plugins
add` against a raw.githubusercontent.com URL. Amp rejects that outright:

  Error: For now, only https://ampcode.com/@amp/plugins/*.ts and
  https://ampcode.com/@amp/plugins/*.ts URLs are allowed.

Verified on Amp 0.0.1787045288. Nothing is written, so the documented path
to the watcher never worked for anyone.

docs/amp.md already contradicted itself about this: 390 lines below the
install block it states that Amp "restricts `amp plugins add` ... to
Amp-hosted plugins" and hands out an atomic curl for elixir-phoenix.ts. The
install instruction was simply the wrong half of the contradiction. Both
call sites now use that same curl + mv pattern against the standalone
repository's stable branch, verified to fetch bytes identical to the
canonical target. The update section loops over both plugins rather than
only the workflow one.

Also raises the phx-watch-pr harness subprocess timeout from 60s to 240s.
The harness drives a fake clock with real 80ms flushes -- advance() runs up
to 21 per call across 23 calls -- so it spends ~59s waiting for ~3s of CPU.
Consecutive local runs took 58.9s, 60.4s, and 73.9s, so a required check
was passing or failing on runner load alone. The harness is unchanged;
shortening the flush would swap a timeout flake for a race.

Fixes a paragraph-join in README introduced when the watch-pr block was
merged forward in #132.
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.

2 participants