feat(cli): load a native application and run it from the CLI

CH
4d ago
+2735-94

Closes #184. Stacked on #211 (→ #207 → #205).

Adds loadable native applications and the CLI that runs them.

What changed

  • @mitome/core: defineMitome(options). This typed producer composes:

    • an ordinary program,
    • native infrastructure Layers,
    • Providers, with a Default Model and ordered fallbacks,
    • an explicit CLI parseInput/renderResult mapping,
    • optional process-local serving Hosts.

    Requirements that are left open are compile errors (see test/application.types.ts). The original program, Layer and Provider types are preserved.

  • acquire() works in this order:

    1. Validates the selection before acquiring anything.
    2. Builds infrastructure once.
    3. Provisions the Model lazily. An explicit --model never falls back. Configured fallbacks are tried in order, and each failed attempt is released before the next.
    4. Unwinds a partial startup.
    5. Becomes ready only once every Host has started.
  • Application:

    • Serves fresh application-owned Sessions. Each Turn binds its own Turn Scope, never the acquisition Scope.
    • Retains idle Sessions until close or shutdown.
    • Reports a serving Host failure without restarting it or touching healthy Hosts.
    • Shutdown closes admission, cancels and drains all owned work, and only then releases the Model and infrastructure. It is idempotent, and the library never exits the process.
  • CLI commands: mitome run --app <file> [--provider] [--model] [--grace] [input], mitome providers and mitome auth status|login|logout. All load the same --app default export; there is no implicit discovery.

  • CLI output and exit behaviour:

    • stdout carries only the rendered result. Logs and defects go to stderr.
    • --grace (default 5s) bounds cleanup after a signal, after normal completion, and after a failed startup. Expiry exits 1.
  • Docs: new applications.mdx and cli.mdx. CONTEXT.md no longer lists the deleted vocabulary. Codex credential errors now name the real auth login command.

Review

The work went through one design review, an initial implementation, and three rounds of independent verification plus spec, standards and simplicity review. That found and fixed:

  • Session close could free shared dependencies early. Session.close detached its Scope before draining, which could release them under a running cleanup.
  • stdout was not clean. Logs and runtime defects were printed to stdout.
  • --grace didn't always apply. It covered only signals; normal completion and failed-start cleanup are now bounded too.
  • A failing shutdown notification skipped resource release.

Each fix has a regression test that fails without it.

Known limitation (documented in cli.mdx): when a native Layer fails while it is being built, Effect rolls back that Layer's own resources before the application can start shutting down. If that rollback hangs, --grace only bounds it after SIGINT/SIGTERM.

Verification

  • bun run build|check|test -- --force all exit 0 (core 104, cli 19, providers 381, create-mitome 11 tests).
  • Independent offline runs of the compiled binary against a scripted-LanguageModel fixture, with no credentials and no network:
    • one-shot runs from an argument and from stdin;
    • unknown, unqualified or mismatched selection errors, with nothing acquired;
    • offline providers and auth status;
    • failed-start unwinding, including a held release that is bounded by grace;
    • a failing program;
    • SIGINT drain, exiting 130.

Not exercised: the interactive OAuth auth login flow, and real Providers over the network.