Skip to content

Align cargo-hauler with Agent Bundle meta-framework architecture (#592) and delete framework workarounds as upstream lands #107

Description

@ScriptedAlchemy

Goal

Use cargo-hauler as a reference consumer of Agent Bundle's #592 architecture rather than preserving workarounds that exist only because current framework surfaces are split.

This is an umbrella migration issue. Do not rewrite working behavior before the relevant upstream capability lands.

1. Composite plugin root / distribution

Blocked on ScriptedAlchemy/agent-bundle#555.

Current cargo-hauler still encodes the old per-target artifact model in:

  • agent-bundle.config.ts comments (artifact/<target>);
  • README.md and docs/install.md (artifact/<host>);
  • AGENTS.md;
  • src/cli/dashboard.ts path heuristics;
  • tests/version-consistency.test.ts;
  • packed/route tests that open artifact/cursor, etc.;
  • package files/installation prose.

After #555:

  • one artifact/ root should contain selected Claude/Codex/Cursor/portable projections;
  • install/doctor should point at the root, not artifact/<host>;
  • tests should inspect agent-bundle.manifest.json / host manifest pointers instead of hard-coded partition paths;
  • npm/Git/local delivery should describe the same plugin root.

Do not preserve compatibility path logic in cargo-hauler itself; Agent Bundle owns any legacy artifact probing.

2. Delete duplicated CLI schema contracts

Blocked on ScriptedAlchemy/agent-bundle#593.

src/cli/status.tsx re-declares statusInputSchema inline because static argv extraction cannot follow the canonical imported schema. tests/schema-compat.test.ts then pins the copy to src/lib/protocol-schemas.ts.

Once #593 lands:

import { statusInputSchema, statusResultSchema } from '../lib/protocol-schemas.js';
export const inputSchema = statusInputSchema;
export const resultSchema = statusResultSchema;

Delete compatibility tests whose only purpose is preventing framework-forced schema drift.

Audit the remaining CLI/MCP pairs (request, result, await, kill, last, log) for the same duplication and share contracts/domain execution wherever the presentation semantics permit it.

3. Delete the hand-written MCP App transport/protocol layer

Blocked on ScriptedAlchemy/agent-bundle#594.

src/mcp/hauler/apps/dashboard.tsx currently owns a local JSON-RPC client over window.parent.postMessage('*'), request ids/timeouts, tools/call envelopes, structured-result unwrapping, and many unknown protocol interfaces that duplicate the route result schemas.

Once #594 lands, the App should consume the generated typed route client and keep only dashboard state/view logic.

Desired shape:

const status = await client.tools.hauler.hauler_status({ limit: 40 });
const detail = await client.tools.hauler.hauler_result({ ticket });

No local knowledge of JSON-RPC ids, structuredContent envelope shape, parent bridge semantics, or manually mirrored server protocol types.

4. Replace checkout-only hauler dashboard

Blocked on ScriptedAlchemy/agent-bundle#564 and #594.

src/cli/dashboard.ts is ~framework integration glue:

  • locate checkout/artifact by relative paths;
  • crawl node_modules for Agent Bundle's package manifest;
  • spawn agent-bundle serve-app;
  • parse its human stdout with a regex to recover the URL;
  • manually relay abort to SIGTERM;
  • cannot run from the npm package or installed plugin.

After #564, delete this implementation and use the framework-generated production browser command/host. hauler dashboard should work from the same installed composite plugin root as the MCP server and routed CLI, with no Agent Bundle checkout dependency.

The application should configure/expose hauler/dashboard; Agent Bundle owns serving, browser opening, lifecycle and URL/result protocol.

5. Bring fast shell hooks back into the canonical event model

Blocked on ScriptedAlchemy/agent-bundle#595.

cargo-hauler #90 correctly moved high-frequency shell hooks to hooks.beforeTool.handler / hooks.afterTool.handler: rendered event routes cost ~0.2 s per shell command pair before they could reject unrelated commands.

This workaround should remain until #595 can emit a physically cheap preflight gate.

Afterward:

6. Provider cost

src/providers/hauler-daemon.ts probes daemon health on every non-event route request. This is acceptable today but should be revisited once #595 supports lazy provider materialization/declared provider needs.

Routes that only need static/help/render information should not probe the daemon merely because the provider exists globally. Keep the probe where domain semantics require a fresh health snapshot.

7. Keep domain/runtime boundaries

Do not move cargo orchestration into Agent Bundle. cargo-hauler should continue to own:

  • daemon/broker scheduling;
  • lane/admission/folding semantics;
  • ledger/protocol domain schemas;
  • Cargo parsing/rewrite policy;
  • metrics/savings calculations;
  • dashboard domain view models.

Agent Bundle should own:

  • route discovery/contracts;
  • host projection;
  • execution context;
  • event envelope/projection;
  • App transport;
  • browser serving;
  • artifact/package/install mechanics.

Acceptance

  • No documentation/tests assume artifact/<host> after #555 adoption.
  • No CLI route duplicates a canonical schema solely for static extraction after #593.
  • Dashboard contains no raw MCP Apps JSON-RPC/postMessage client after #594.
  • hauler dashboard works from the installed/npm plugin root without a framework checkout after #564.
  • Fast shell hooks use the canonical event graph without regressing Hook overhead: ~100 ms per PreToolUse and per PostToolUse on every Bash call #90 after #595.
  • Provider health probing is paid only where required once lazy provider support exists.
  • cargo-hauler remains a useful end-to-end reference fixture for Agent Bundle's Application IR -> Projection IR -> Artifact IR architecture.

Activity

ScriptedAlchemy commented on Sep 5, 2026

@ScriptedAlchemy
OwnerAuthor

Additional upstream item from the same audit: ScriptedAlchemy/agent-bundle#596 tracks collapsing the duplicated CLI/MCP operation modules themselves, not just their schemas.

cargo-hauler currently has parallel pairs such as src/cli/request.tsx + src/mcp/hauler/tools/hauler_request.tsx and src/cli/status.tsx + src/mcp/hauler/tools/hauler_status.tsx. They correctly share domain functions/documents, but the framework still requires two route implementations to get an idiomatic CLI (positionals, short names, flag mapping) and an MCP tool.

Once #596 lands, add to this umbrella's acceptance: request/status/await/result/kill/last/log each have one canonical operation implementation with MCP and CLI projections, while preserving current CLI UX.

ScriptedAlchemy commented on Sep 5, 2026

@ScriptedAlchemy
OwnerAuthor

Deep-dive decomposition filed from this umbrella:

These sharpen the boundary from the umbrella: cargo-hauler keeps cargo scheduling/daemon/ledger semantics; Agent Bundle should own route relationships, observed request identity, projections, execution lifecycle, notice delivery, App transport, browser hosting, and host capability resolution.

ScriptedAlchemy commented on Sep 5, 2026

@ScriptedAlchemy
OwnerAuthor

Boundary correction after the deeper review: #107 should be read as removing framework-boundary workarounds, not migrating cargo-hauler product architecture into Agent Bundle.

Keep cargo-hauler authoritative for the daemon, scheduler, queue/lane/admission policy, process ownership, ticket/ledger state, completion semantics, Cargo parsing, metrics, output handling, folding/dedupe policy, and product-specific persistence/retry behavior.

Agent Bundle should only replace generic plugin plumbing where it already has or is adding a reusable primitive: route/projection duplication, host event normalization, request identity/workspace observation, App transport/browser hosting, capability negotiation, packaging/install, and optional generic notice delivery.

In particular, do not move stop-deny state, completion state, or daemon/ledger state into Agent Bundle merely because src/state.ts exists. Adopt framework state/notices only where they replace generic transport/infrastructure mechanics without taking over cargo-hauler domain authority. cargo-hauler#116 has been narrowed to reflect this.

ScriptedAlchemy commented on Sep 5, 2026

@ScriptedAlchemy
OwnerAuthor

agent-bundle PR #601 merged as 0d4a37cef764e54acd93b9d6eb780fa61e5e02eb, completing the typed MCP App client and shared bridge prerequisite for §3. Its read-only dashboard dry-run removed 73 lines of local JSON-RPC/pending-request/envelope plumbing (1,984 → 1,911), with a self-contained browser bundle and generated route typing.

ScriptedAlchemy commented on Sep 5, 2026

@ScriptedAlchemy
OwnerAuthor

Upstream status for the migration, as of agent-bundle main 512ddaac3 (10:10 UTC):

  • #555 W1 composite root landed (agent-bundle #578, 62b69c068): one artifact root, host projections chosen by targets, install/doctor read the root's host plugin.json only. This is the artifact/<host> coupling listed in §1.
  • #594 typed MCP App client + shared bridge landed (#601, 0d4a37cef): replaces the hand-written JSON-RPC/postMessage transport in dashboard.
  • #595 preflight gates + lazy providers landed (#618, ef2abbacc): replaces the parallel fast-hook registration model.
  • #564 first-class web surface landed (#620, 512ddaac3): <plugin> web from the installed artifact. Note: that PR removed the agent-bundle/serve-app-command export that cargo-hauler chore: re-pin agent-bundle preview d30d9acb6; hauler dashboard uses spawnServeApp #122 adopted for spawnServeApp; the next agent-bundle preview bump must replace src/lib/dashboard-serve.ts with the generated web surface rather than keep the spawn helper.
  • Still open upstream: #604 authoritative manifest v2 (consumers read the root through the manifest — the last piece §1 waits on), #596 CLI projections (#616), #619 compiler evidence.

Plan: one migration PR here after agent-bundle #604 merges, covering §1 (single root), the bridge, the gates, and web in one preview bump, so cargo-hauler moves once.

ScriptedAlchemy commented on Sep 6, 2026

@ScriptedAlchemy
OwnerAuthor

Landed in #135 (squash bf9d3a4), released as cargo-hauler@0.6.8 via #137, installed on the owner machine for Claude, Codex, and Cursor from the composite root (cargo-hauler-install install <host> --replace; Codex needed codex plugin marketplace remove cargo-hauler-marketplace first because its registration pointed at the pre-composite artifact/codex), daemon restarted, bin/cargo-hauler.mjs web verified from the installed Claude root.

Workaround → replacement:

Workaround Replacement
artifact/<host> knowledge in config comments, README, docs/install.md, AGENTS.md, dashboard SKILL, version/packed/entry-location tests, pluginCachePath regex one artifact/ composite root; targets: ['claude','codex','cursor','portable'] selects projections (agent-bundle#578)
src/cli/dashboard.ts + src/lib/dashboard-serve.ts (spawnServeApp, agent-bundle/serve-app-command) web: { apps: [...] } in agent-bundle.config.ts; the installed plugin's own bin/cargo-hauler.mjs web (agent-bundle#620/#628/#635/#646)
hand-written JSON-RPC/postMessage transport in apps/dashboard.tsx createAppClient from agent-bundle/app (agent-bundle#601)
config-declared fast hooks (hooks.* block, src/hooks/fast-path/*) src/events/tool/{before,after}.tsx event routes with before.preflight.ts / after.preflight.ts gates and providers: [] (agent-bundle#618); the unprobed daemon-health state that only the provider path produced is gone
duplicated statusInputSchema and the src/cli/{status,log,last,await,result,request,kill}.tsx twins of the MCP tools one canonical tool each with a colocated <tool>.cli.ts projection (mapInput for request's positionals/--after), surfaceNames(context) for CLI-vs-MCP naming; --help and per-command output snapshotted before/after, unchanged (agent-bundle#616/#593)
framework-generated state under cargo-hauler's own dir framework state root (agent-bundle#640/#642/#647); CARGO_HAULER_STATE_DIR remains the daemon's
per-host packed tests tests/route-unit/packed-install.test.ts: installs Claude/Codex/Cursor into isolated HOMEs, opens the installed MCP server, serves web

Kept: #95's bounded status summary.

Remaining items — none blocking, no shim written:

  • tool/after queries the daemon twice when tickets finished, because a preflight cannot hand its result to the route. Filed as Event preflight: let the gate hand a value to the rendered route agent-bundle#661; documented in after.preflight.ts. Cost is one bounded round trip only when tickets finished.
  • Machine-only: an existing Codex marketplace registration from the artifact/<host> era has to be removed by hand once before --replace succeeds (AB7004).

ScriptedAlchemy commented on Sep 6, 2026

@ScriptedAlchemy
OwnerAuthor

Upstream follow-up: ScriptedAlchemy/agent-bundle#664 merged as d94223a663c5be3fda85f8809285512b5676e634. Event preflights can now return { outcome: 'execute', data }, and the route receives that typed strict-JSON value as props.preflight across standalone/shared-runtime execution. cargo-hauler can now delete the second tool/after daemon query and reuse the preflight result. The superseding agent-bundle main CI run is green: https://github.com/ScriptedAlchemy/agent-bundle/actions/runs/34009548255

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions