@arki/dot
archivefor @arki/[email protected] · Tier 1: the stack
TypeScript-first application composition framework for the ARKI package family.
Install
bun add @arki/[email protected]Other package managers
npm install @arki/[email protected]
pnpm add @arki/[email protected]
yarn add @arki/[email protected]Release health for @arki/[email protected]
Doc examples
No example report was recorded for this version.
Open gaps
2 release checks fail · 6 gaps were found by demos
- check
file-agents-md - check
pkg-engines - Plugin hook spans are created with tracer.startSpan (not startActiveSpan), so work done i… found by drop-studio
- Plugins do not declare their source package found by drop-studio
- Instrumentation scope version is hard-coded (0.1.0) while the package is 0.4.1, and plugi… found by drop-studio
- Running app.boot() under context.with(ROOTCONTEXT.setValue(key, v), …) stalls boot under… found by drop-studio
- The dot bin runs under Node (#!/usr/bin/env node) and cannot import a .ts app file there… found by drop-studio
- createAppRuntime(app).get() returns a DotApp type that is not assignable to the result ty… found by faultline
Used by demos
No demo uses this package yet.
Runtimes
No engines field, so no runtime requirement is declared.
Benchmarks
No benchmarks are published for this version.
README
TypeScript-first application composition framework for the ARKI package family.
@arki/dot is the kernel that wires pips, lifecycle hooks, dependency
graphs, and diagnostics into a deterministic application boot. It gives library
authors a stable contract for declaring how their package participates in an
app, and gives app developers a single place to wire those packages together.
What is a pip?
A pip is the unit a DOT app is built from — one self-describing, lifecycle-aware piece of an application. Each pip:
- declares a name, version, and the kinds of services it provides;
- runs a 5-hook lifecycle —
configure→boot→start→stop→dispose; - publishes typed services to a shared, type-safe registry that later pips can read from;
- composes deterministically — pips boot in declaration order and dispose in reverse.
The name comes from the small dots on dice, dominoes, and music notation: each pip is one small mark, and the combination of pips is what gives the app its value. Two pips on a die make a value of two; six pips make six. The pips are the app — not optional add-ons to a hidden core.
import { defineApp } from '@arki/dot';
import { env } from '@arki/env/dot'; // env pip
import { db } from '@arki/db/dot'; // db pip
import { kv } from '@arki/kv/dot'; // kv pip
const app = await defineApp('orders')
.use(env({ schema: { /* ... */ } })) // 1st pip — provides services.env
.use(db({ relations })) // 2nd pip — provides services.db
.use(kv({ url: process.env.KV_URL! })) // 3rd pip — provides services.kv
.boot(); // pips boot in declaration order
await app.services.db.query(/* ... */);
await app.dispose(); // pips dispose in REVERSE orderEach /dot subpath exports a pip for that package. The subpath names
the framework the adapter targets (DOT), not the unit (which is a pip).
Why not "plugin"? Plugins suggest optional add-ons to a core. DOT's reality is the opposite: there is no hidden core — the pips are the app. "Pip" names that truth, and ties the framework to the DOT name etymologically (a dot, a pip, a small mark that gains meaning by combining with others).
Installation
npm install @arki/dot
# or
bun add @arki/dotQuick start
import { defineApp, defineDotPip } from '@arki/dot';
const billingPip = defineDotPip({
name: 'billing',
version: '1.0.0',
configure(ctx) {
// Validate config, register schemas, no I/O.
},
async boot(ctx) {
// Open connections, register providers.
return { stripe: makeStripeClient() };
},
async start(ctx) {
// Begin processing — workers, subscriptions, schedulers.
},
async stop() {
// Stop processing — drain workers, unsubscribe.
},
async dispose() {
// Close connections, free resources.
},
});
const app = defineApp('acme')
.use(billingPip);
await app.configure();
await app.boot();
await app.start();
// app.manifest, app.diagnostics — agent-friendly envelopes.
await app.stop();
await app.dispose();Pip authoring
defineDotPip(config) accepts five lifecycle hooks. Each receives a
phase-specific context with services contributed by earlier pips:
| Hook | Purpose |
|---|---|
configure | Validate static config; declare schemas, routes, services. No I/O. |
boot | Open connections; register providers; return a typed kit. |
start | Begin processing (workers, subscribers, schedulers). |
stop | Stop processing in reverse dependency order. |
dispose | Free resources after stop. |
Pips can declare dependencies on others by name. The kernel computes a topological order and runs hooks deterministically — same input, same order, every time.
Lifecycle
defineApp(name) returns a builder. Calling .use(pip) accumulates
pips. The lifecycle then flows:
defined ──configure()──▶ configured ──boot()──▶ booted ──start()──▶ started
│
disposed ◀──dispose()── stopped ◀──stop()───────┘
boot() runs configure() implicitly if you skipped it. start() runs
boot() implicitly. stop() and dispose() always run in reverse dependency
order, even when an earlier hook failed — failure isolation is part of the
contract.
CLI
@arki/dot ships a small CLI for scaffolding and inspecting apps:
# Scaffold a minimal DOT app (package.json, tsconfig, app entrypoint,
# env schema, AGENTS.md, README, gitignore, vitest boot test).
dot new my-app
# Preview the file operations without writing anything.
dot new my-app --dry-run --json | jq '.operations'
# Print the app manifest as a structured envelope.
dot explain --app ./my-app.ts
# Run boot-time diagnostics; non-zero exit if any check fails.
dot doctor --app ./my-app.ts
# Every command supports --json for agent-friendly output.
dot explain --app ./my-app.ts --json | jq '.data.pips'The CLI emits the same envelope shape as the in-process diagnostics snapshot
(app.diagnostics), so the same downstream tools can consume either.
dot new <app-name>
Scaffolds a minimal DOT app under <app-name>/ (override with --target).
The scaffold ships a defineApp(...) entrypoint wired to @arki/env/dot,
a vitest that boots the app and asserts the manifest shape, and an
AGENTS.md documenting verification commands and the public/private
boundary for agents working in the generated tree. Pass --dry-run --json
to inspect the exact file operations (path, action, contentHash,
contentBytes, reason) before committing them to disk; --force
overwrites pre-existing files in the target directory.
Templates live at templates/app-minimal/ and
ship with the published tarball.
Architecture
@arki/dot is intentionally small: it defines the contracts (pip shape,
lifecycle hooks, manifest schema, diagnostics envelope) and runs them. Adapters
that bridge databases, queues, auth providers, and HTTP routers live in their
own packages and consume @arki/dot as a peer dependency.
This keeps the kernel free of optional dependencies and lets each adapter ship at its own cadence.
Documentation
The full docs live in docs/:
- Principles — read first. The five rules every API, error, and PR is measured against. Slightly playful, very precise.
- Quickstart — boot your first app in five minutes.
- Pip authoring — write your own
DotPip. - Lifecycle — the 5-hook contract.
- Diagnostics —
app.manifest,app.diagnostics,dot explain,dot doctor. - Adapter authoring — expose your package as a DOT pip.
- Agent guide — how coding agents inspect, modify, and verify DOT apps.
- Release policy — SemVer and deprecation.
Agent-discoverable index: llms.txt.
License
MIT — see LICENSE.
Public imports
This version has no API index.