Skip to content

Meta-framework architecture: one application graph, capability-driven projections, one execution kernel #592

Description

@ScriptedAlchemy

Decision

Agent Bundle should converge on one coherent meta-framework architecture:

one application, one route graph, one execution kernel, one compiler pipeline, one manifest, one composite artifact, many host projections.

The product should feel like Next.js for agent-host plugins: authors express application intent through conventions and a small public API; compiler/runtime machinery owns host differences, packaging, transport, and projection.

This issue is the architectural umbrella for simplification work that cuts across #555 (composite root), #564 (browser/web), the route framework, execution/runtime plumbing, compiler profiles, Workbench, testing, and distribution.

This is not a request to rewrite working subsystems immediately. It establishes the direction so new work stops adding parallel mini-frameworks.

Product boundary

Agent Bundle's job is:

Compile one typed agent application into native experiences across agent hosts.

Core scope:

  • filesystem-routed application structure;
  • typed route contracts;
  • shared execution context;
  • host capability resolution;
  • host projections;
  • self-contained composite artifact;
  • CLI / MCP / browser presentation of the same application;
  • devtools, validation, testing, and distribution around that compiled application.

Do not turn core into a general agent orchestrator, workflow engine, ORM/database framework, deployment platform, LLM abstraction layer, or generic web framework.


1. Make the application graph the canonical source of truth

Today MCP tools/resources/prompts/apps, CLI routes, scripts, events/hooks, providers, layouts, skills, commands, and browser-facing behavior have partially separate discovery/planning paths.

Internally they should lower into one Application IR.

Illustrative shape:

interface ApplicationIR {
  identity: ApplicationIdentity;
  routes: RouteNode[];
  providers: ProviderNode[];
  middleware: MiddlewareNode[];
  assets: AssetNode[];
  capabilities: CapabilityRequirement[];
}

type RouteKind =
  | 'tool'
  | 'resource'
  | 'prompt'
  | 'app'
  | 'command'
  | 'script'
  | 'event'
  | 'page';

interface RouteNode {
  id: string;
  kind: RouteKind;
  source: SourceModule;
  input?: SchemaRef;
  output?: SchemaRef;
  runtime: 'node' | 'browser' | 'worker';
  capabilities: CapabilityRequirement[];
  metadata: Record<string, unknown>;
}

The exact TypeScript shape is not normative. The architectural requirement is.

Required result

Discovery happens once. Every downstream subsystem reads the same graph instead of rediscovering semantics independently.

src conventions
      ↓
 route discovery
      ↓
 Application IR
      ↓
 capability resolution
      ↓
 host / CLI / browser projections

2. Separate Application IR, Projection IR, and Artifact IR

Do not let adapters simultaneously own application semantics, host translation, and filesystem layout.

Target compiler phases:

Source
  ↓
Application IR        host-independent semantics
  ↓
Projection IR         how Claude/Codex/Cursor/portable represent it
  ↓
Artifact IR           files, manifests, executables, assets
  ↓
Composite plugin root

Illustrative contracts:

interface ProjectionIR {
  host: HostId;
  routes: ProjectedRoute[];
  hooks: ProjectedHook[];
  manifests: ManifestNode[];
  diagnostics: Diagnostic[];
}

interface ArtifactIR {
  files: ArtifactFile[];
  executables: Executable[];
  manifests: Manifest[];
}

Adapters should trend toward:

project(application, hostCapabilities): ProjectionIR

Common artifact assembly should own deterministic merging/collisions/self-containment rather than each adapter behaving like a partial compiler.

3. targets are projection selection, not architecture

#555 correctly separates host selection from artifact layout.

Longer term, code and docs should consistently use projection for claude | codex | cursor | portable. The existing config key may remain targets for compatibility, but internally it should not imply:

  • output partition;
  • artifact type;
  • runtime type;
  • distribution form;
  • application identity.

Application declarations should prefer static capability requirements over host-name conditionals.

Prefer:

export const config = {
  requires: ['hooks.preTool']
};

instead of making authors encode:

targets: ['claude', 'codex']

when the actual intent is a capability.

The compiler resolves:

application requirement
        ↓
host capability table
        ↓
supported projection / diagnostic

Host-specific declarations remain an escape hatch when semantics really are host-specific.

4. One execution kernel

MCP, CLI, scripts, browser-backed execution, and host event routes should use one request/execution kernel wherever their semantics overlap.

Canonical context should be one model:

interface AgentContext {
  request: RequestContext;
  host: Observed<HostContext>;
  workspace: Observed<WorkspaceContext>;
  session: Observed<SessionContext>;
  agent: Observed<AgentContextValue>;
  capabilities: CapabilityView;
  providers: ProviderValues;
  state: StateAccess;
  lineage: LineageAccess;
  notices: NoticeAccess;
  signal: AbortSignal;
}

Keep the existing available / unavailable / observed-value discipline. Do not manufacture host/session identity where none exists.

Execution should conceptually be:

request
  ↓
context construction
  ↓
providers
  ↓
middleware/effects
  ↓
layout
  ↓
route
  ↓
response transforms
  ↓
projection renderer

Providers, layouts, middleware, event effects, and route handlers must have one documented ordering model rather than independently evolving precedence rules.

5. Events/hooks should lower into the same graph

Keep src/events/** because the convention is good.

Do not grow events into a second application framework. Canonical lifecycle events should lower into execution effects/nodes in the same Application IR, with the host adapters translating them to native hook formats.

The framework should have one model for:

  • before/after route;
  • before/after tool;
  • session start/stop;
  • agent start/stop;
  • host-native lifecycle mapping.

Host hook wrappers are projections of semantic events, not the semantic source of truth.

6. One compiler service with runtime profiles

Recent audits exposed drift between Rslib, Rsbuild, MCP App, Workbench, and example compiler paths. Fixing individual bugs is necessary, but the architecture should make profile drift difficult.

Introduce/centralize a compiler service with explicit environments/purposes:

compiler.compile({
  entry,
  runtime: 'node' | 'browser' | 'worker',
  purpose: 'route' | 'app' | 'cli' | 'runtime' | 'library',
  mode: 'development' | 'production'
})

All profiles should share framework-owned policy for:

  • reserved module aliases;
  • React/JSX setup;
  • compiler diagnostic extraction;
  • source-map policy;
  • self-containment;
  • externalization rules;
  • legal comments;
  • cache policy;
  • module-size reporting;
  • compiler escape-hatch validation.

Rslib/Rsbuild/Rspack remain implementation details behind this layer.

7. Browser is a runtime/projection, not a separate mini-framework

Align #564 with this architecture.

The production browser host is valuable, but web should not create an independent registration/discovery/config universe when an MCP App already represents a browser-capable route/view.

Preferred model:

App/page route
   ├── server execution/data contract
   └── browser view
          ↓
      Browser projection
          ↓
MCP App / Workbench / `<plugin> web`

A route/view should be reusable across MCP-host embedding and standalone browser hosting. serve-app, Workbench preview, and <plugin> web should use the same browser runtime/bridge.

Avoid adding src/web/** as a second routing framework unless there is a browser-only use case that cannot be expressed through the canonical route graph.

8. Make Agent Document / structured result the universal response boundary

Rendered routes should produce one canonical response representation that projections lower into:

  • MCP content + structuredContent;
  • human CLI output;
  • JSON CLI output;
  • Workbench inspection;
  • browser presentation where appropriate.

Raw MCP CallToolResult should be an interop boundary, not the primary application programming model.

Keep structured data separate from presentation so the same route can be consumed by agents and humans without duplicate implementations.

9. Make state deliberately boring

Core state responsibilities:

  • scope;
  • identity/namespace;
  • schema/version;
  • transaction/concurrency semantics;
  • durability selection;
  • migration;
  • lifecycle.

Application owns domain data.

Lineage/notices may build on shared persistence primitives, but application authors should not need to understand their storage implementation.

Do not expand core state into an ORM or general data layer.

10. Prefer generic runtimes + manifests over generated wrapper proliferation

Where possible, move semantics from generated source templates into small generic runtimes driven by manifest data.

Prefer:

generic hook runtime + hook descriptor

over multiple generated host-specific source templates carrying duplicated business rules.

Generated wrappers may still be required for host contracts and self-contained artifacts, but should remain thin projection shells.

11. Make agent-bundle.manifest.json the compiled application database

The manifest should become the authoritative compiled description consumed by:

  • Doctor;
  • Workbench;
  • install/uninstall;
  • dev host sync;
  • artifact validation;
  • eval harnesses;
  • CLI inspection;
  • test helpers.

It should describe application identity, selected projections, routes/surfaces, capabilities, executables/assets, and provenance sufficiently that downstream tools do not need to infer architecture from filesystem probing.

Filesystem conventions remain host output contracts; they should not be the internal database of the framework.

12. Distribution is downstream of compilation

#555 is the first part of this.

Desired model:

agent-bundle build
        ↓
canonical composite plugin root
        ↓
Git / npm / local / marketplace distribution metadata

Packaging must not recompile the application into a different product shape.

The plugin's core bytes and semantics should be distribution-neutral. npm/Git/local differences belong in catalog/package wrappers and install instructions.

13. Reduce public configuration

The framework should aggressively infer what it can from conventions.

A normal app should trend toward:

export default defineConfig({
  plugin: { name: 'repo-ops' }
});

Configuration should focus on values that cannot be inferred safely:

  • identity;
  • explicit capability/permission policy;
  • distribution metadata;
  • runtime policy;
  • rare compiler escape hatches.

Avoid config that merely re-registers files already discoverable from src/**.

14. Workbench is DevTools over the compiler/runtime

Workbench should consume Application IR / manifest / execution protocols and provide:

  • graph inspection;
  • route invocation;
  • context/provider/state inspection;
  • event tracing;
  • projection comparison;
  • App/browser preview;
  • diagnostics;
  • generated artifact inspection.

Do not give Workbench a separate semantic model that production does not use.

15. Present one simple testing model to plugin authors

Internal repo testing can remain highly specialized. Public plugin testing should present three levels:

1. application semantics   — route/component test, no host
2. projection semantics    — compiled in-memory host representation
3. native-host proof       — actual Claude/Codex/Cursor process

Public helpers should reflect these levels rather than exposing the complexity of Agent Bundle's own CI pool architecture.


Relationship to current work

#555 — composite root

Aligned and foundational. It should be treated as the Artifact IR/output simplification slice of this architecture.

One terminology refinement: targets select host projections. Do not let the implementation reintroduce target identity into shared application/runtime identity just because the config key is still named targets.

#564 — production browser/web

Keep, but align. Implement browser hosting as a projection/runtime over existing App/page routes rather than a new independent surface registry. Reuse one browser bridge across MCP host embedding, Workbench, serve-app, and <plugin> web.

#566 / #572 / #590

Audits remain valid. Where they identify duplicated compiler/doc/test plumbing, prefer fixes that consolidate the architecture rather than only synchronizing copies.

#588 / #591

Self-containment validation is aligned. Long term it belongs to common Artifact IR validation and should be applied uniformly to every compiled executable surface.


Sequencing

Do not attempt one giant rewrite.

Suggested order:

  1. Finish composite-root semantics (Emit one composite plugin artifact; use targets to select the host projections inside it #555).
  2. Define/document Application IR, Projection IR, Artifact IR boundaries without changing public behavior.
  3. Make the manifest authoritative for compiled graph/projections/artifact inventory.
  4. Route all compiler profiles through shared compiler policy.
  5. Converge execution context/pipeline.
  6. Move host adapters toward pure projection functions.
  7. Implement First-class web surface (production): ship a browser host for the plugin's MCP Apps inside the artifact, openable from the installed CLI (<plugin> web); /web in dev for parity #564 on the shared browser runtime/projection.
  8. Remove obsolete duplicate planners/wrappers/probing as each consumer moves to the canonical IR/manifest.

Acceptance criteria

  • There is one documented canonical Application IR used by all executable route kinds.
  • Host adapters consume Application IR and emit Projection IR rather than owning independent application discovery.
  • Artifact assembly consumes Projection IR and produces one deterministic Artifact IR/composite root.
  • agent-bundle.manifest.json is authoritative enough that Workbench/install/doctor/test/eval do not rediscover application structure from path probing.
  • MCP, CLI, script, event, and browser-capable routes share one execution context and ordering model where applicable.
  • Host compatibility is primarily capability-driven; direct host-name targeting is exceptional.
  • Compiler profiles share framework-owned resolution/diagnostic/self-containment policy.
  • Browser hosting reuses the same App route/view and bridge in MCP hosts, Workbench, serve-app, and production <plugin> web.
  • Distribution form does not change application compilation semantics or artifact structure.
  • Public docs explain the framework with a small mental model: routes, context, providers, state, capabilities/projections, config.
  • Internal implementation concepts such as artifact planners, host shims, epoch stores, receipts, and compiler profiles are not required knowledge for ordinary plugin authoring.

Non-goals

  • preserving accidental pre-1.0 internal APIs;
  • introducing a second routing system for browser pages;
  • replacing MCP or native host protocols;
  • hiding genuine host capability differences;
  • forcing every route kind to have identical runtime semantics;
  • one giant rewrite PR.

Activity

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 requestmeta-frameworkAgent Bundle compiler-coupled meta-framework

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions