tagma-mono
Tagma monorepo - local AI task orchestration SDK and visual editor.
Repository Structure
tagma-mono/
|-- packages/ public npm packages (bun workspace: packages/*)
| |-- types/ @tagma/types Shared contracts and small runtime helpers
| |-- core/ @tagma/core Runtime-independent orchestration core
| |-- runtime-bun/ @tagma/runtime-bun Bun runtime implementation
| |-- sdk/ @tagma/sdk Public SDK and helpers
| |-- driver-codex/ @tagma/driver-codex Codex CLI driver plugin
| |-- driver-claude-code/ @tagma/driver-claude-code Claude Code CLI driver plugin
| |-- middleware-lightrag/ @tagma/middleware-lightrag LightRAG knowledge-graph retrieval middleware
| |-- trigger-webhook/ @tagma/trigger-webhook HTTP webhook trigger plugin
| `-- completion-llm-judge/ @tagma/completion-llm-judge LLM-as-judge completion plugin
|-- apps/ private app workspaces tracked in this monorepo (bun workspace: apps/*)
| |-- editor/ tagma-editor Visual pipeline editor (React + Vite + Bun/Express)
| `-- electron/ tagma-desktop Electron shell + Bun-compiled sidecar for desktop builds
|-- package.json monorepo root (bun workspaces)
`-- .gitignore
The five plugin packages (driver-codex, driver-claude-code, middleware-lightrag, trigger-webhook, completion-llm-judge) also serve as reference implementations. They cover the four plugin capability categories: drivers, middleware, triggers, and completions. The SDK's built-in driver is opencode; all other drivers ship as plugins.
Quick Start
Prerequisites: Bun 1.3.x for workspace install/build/test, plus Node.js 22+ for
repository maintenance scripts that intentionally run with node.
bun run dev:editor:rebuild
This one-command path installs dependencies, fully rebuilds the shared packages and plugins, then
starts the editor. Use it when you do not want to distinguish which workspace changed. The regular
bun run dev:editor remains the faster path when only editor source changed.
Task Dataflow
Every task can consume inputs and publish outputs.
inputsare values the task needs.outputsare values the task produces.- Command tasks use inputs in
{{inputs.name}}. - Prompt tasks receive inputs as context and produce outputs as structured JSON.
- When names match, Tagma connects them automatically.
- Use
fromonly when you need to disambiguate, rename, or read raw streams. - Command placeholders are verbatim by default. Use
| shellquotefor string inputs in shell commands; otherwise a value containing shell syntax can change the command that runs.
YAML uses task-level inputs / outputs; there is no public ports: key.
tasks:
- id: choose_city
prompt: Choose a city for a weekend trip.
- id: weather
depends_on: [choose_city]
command: 'weather --city {{inputs.city | shellquote}}'
inputs:
city:
type: string
outputs:
forecast:
type: string
Finite Self-Repair Workflows
A workflow can rerun a failed pipeline with the previous failure fed back to its AI prompt tasks:
workflow:
kind: graph
name: repair-until-verified
pipelines:
- id: implement
path: .tagma/implement/pipeline.yaml
lifecycle:
max_runs: 3
stop_when: success
repair: true
Self-repair stops on the first successful attempt or after max_runs. It must use a finite
max_runs of at least 2 and stop_when: success. Before each retry, Tagma adds bounded,
redacted task status, exit-code, failure-kind, stdout, and stderr evidence to every prompt task.
When the driver and prior result support it, each prompt task also continues its own previous
agent session; otherwise a bounded, redacted copy of the prior normalized output remains available
as fallback context. An authored continue_from handoff keeps priority over same-task retry state.
Define success explicitly in the referenced pipeline with a final verifier command task, or add
a Completion Check such as completion: { type: output_check, check: 'python verify.py' } to a
prompt task. Verifier commands are language-agnostic: they can run Python tests, cargo test,
go test ./..., bun test, or any project-specific checker whose non-zero exit should trigger
another repair attempt.
Common Commands
Install Dependencies
bun install
# If proxy is blocking:
$env:HTTP_PROXY=''; $env:HTTPS_PROXY=''; bun install --force
# Desktop development also needs the Electron runtime binary:
bun run --filter tagma-desktop ensure:electron
Local Development
bun run dev:editor # Start editor (server + client concurrently)
bun run dev:editor:rebuild # Install, fully rebuild packages/plugins, then start editor
bun run dev:server # Start server only (watch mode)
bun run dev:client # Start Vite client only
bun run dev:desktop:hmr # Launch Electron with a Vite renderer and source sidecar; no package/install cycle
bun run dev:desktop # Ensure Electron runtime, build the desktop chain, and launch the Electron shell
Use bun run dev:editor:rebuild as the safe one-command path after arbitrary repository changes.
It deliberately runs the full bun run build; adding bun run build:incremental afterward would
only rebuild a subset of the same packages a second time and would add no coverage.
For normal editor, Chat, Trial, and server work, use bun run dev:editor and open the Vite URL
(usually http://127.0.0.1:5173). Vite hot-reloads renderer changes and the backend runs under
bun --watch; package, publish, installer download, and reinstall steps are unnecessary.
Use bun run dev:desktop:hmr only when the Electron shell itself matters. Run
bun run --filter tagma-desktop ensure:electron once first. The HMR launcher uses an isolated
apps/electron/.tmp/desktop-hmr-user-data/<pid> profile and automatically selects free renderer
and sidecar ports. Renderer edits hot-reload; restart the command after Electron-main or sidecar
source changes.
Build
bun run build # Build types + core + runtime-bun + sdk + all plugin packages
bun run build:types # Build @tagma/types only
bun run build:core # Build @tagma/core only
bun run build:runtime-bun # Build @tagma/runtime-bun only
bun run build:sdk # Build @tagma/sdk only
bun run build:plugins # Build all plugin packages (drivers + middleware + triggers + completions)
bun run build:drivers # Build driver plugins only
bun run build:middlewares # Build middleware plugins only
bun run build:triggers # Build trigger plugins only
bun run build:completions # Build completion plugins only
bun run build:editor # Build editor client (Vite bundle)
bun run build:editor-sidecar # Compile the editor server into a single-file executable
bun run build:electron # Build the Electron main/preload bundles only
bun run build:desktop # Full chain: types -> core -> runtime-bun -> sdk -> plugins -> editor -> editor-sidecar -> electron
Build order: types -> core -> runtime-bun -> sdk -> plugins. The desktop chain layers the editor client, the compiled Bun sidecar, and the Electron shell on top.
Type Checking
bun run check # Run all type checks
bun run check:types # Check @tagma/types only
bun run check:core # Check @tagma/core only
bun run check:runtime-bun # Check @tagma/runtime-bun only
bun run check:sdk # Check @tagma/sdk only
bun run check:driver-codex # Check @tagma/driver-codex only
bun run check:driver-claude-code # Check @tagma/driver-claude-code only
bun run check:middleware-lightrag # Check @tagma/middleware-lightrag only
bun run check:trigger-webhook # Check @tagma/trigger-webhook only
bun run check:completion-llm-judge # Check @tagma/completion-llm-judge only
bun run check:server # Check editor server only
bun run check:client # Check editor client only
bun run check:tests # Check editor test sources only
bun run check:electron # Check Electron main/preload only
Testing
bun run test # Run all tests
bun run --filter @tagma/sdk test # SDK only
bun run --filter tagma-editor test # Editor only
Full Verification
bun run verify # Text hygiene -> format -> type checks -> lint -> tests -> full desktop build
bun run verify:quick # Same quality gates, but skips the full desktop build
bun run verify:full # Explicit full verification alias
verify keeps running after a failed gate so one run can report problems from
multiple angles. It exits non-zero unless every selected gate passes.
Desktop Packaging
bun run pack:desktop # Build the desktop chain and produce an unpacked electron-builder dir
bun run dist:desktop:win # Build and produce Windows installer (nsis)
bun run dist:desktop:linux # Build and produce Linux AppImage, .deb, .rpm, and .tar.gz
bun run dist:desktop:mac # Build and produce macOS dmg
Each installer also ships platform-matched opencode and bun binaries in resources/opencode/ and resources/bun/, so end users do not need a manual runtime install for bundled AI execution or plugin dependency installation. The versions are pinned via apps/electron/package.json -> tagma.bundledOpencodeVersion and tagma.bundledBunVersion; the OpenCode pin must exactly match apps/editor/package.json -> @opencode-ai/sdk. Bump the matching fields, refresh bun.lock, and re-run a dist:desktop:* command to cut a release with new defaults. OpenCode upgrades ship with Tagma releases; the sidecar's independent OpenCode update route remains a manual recovery interface and is not exposed in the editor UI.
The tagma-desktop package is private and is never published to npm.
Desktop release signing is opt-in in CI. Set TAGMA_SIGN_APP=1 plus the
platform signing secrets to sign installers; local and alpha packaging skip app
signing by default.
Lint & Format
bun run lint # ESLint across packages/ (--max-warnings 0)
bun run format # Prettier write
bun run format:check # Prettier check
Clean
bun run clean # Remove workspace node_modules, dist outputs, and app packaging artifacts
bun run clean:all # Also remove bun.lock
bun install # Reinstall
Publishing
The default flow is CI-driven: bump the public package version fields, push to main, and .github/workflows/publish-npm.yml detects the changed versions and publishes to npm in dependency order. Manual scripts are kept as a local fallback.
1. Bump Version
The public @tagma/* packages can keep independent versions. Bump only the package that changed, or bump every public package from its own current version when a coordinated release is useful:
bun run version <all|package> <patch|minor|major|x.y.z>
# Examples
bun run version sdk patch # bump @tagma/sdk only
bun run version core minor # bump @tagma/core only
bun run version all patch # +0.0.1 on each public package's current version
bun run version @tagma/sdk 0.8.0
The version script updates package version fields and then refreshes the root bun.lock with bun install --lockfile-only --ignore-scripts. A --dry-run updates neither file. Commit and push the package manifest and lockfile changes together. The CI workflow keys off version diffs in packages/*/package.json, not on git tags.
2. Push To main
publish-npm.yml runs on every push to main that touches packages/*/package.json:
- Detect version diffs against the previous commit. Packages whose version is unchanged are skipped.
- Publish each changed package by running the matching
publish:*script in dependency order.
Auth currently comes from the NPM_TOKEN repo secret, written to .npmrc only for the publish job and removed in a cleanup step after publishing.
To re-trigger publish after bumping a package version manually, dispatch the workflow from the Actions tab and pass a JSON array, for example ["types","sdk"]. Valid keys: types, core, runtime-bun, codex, claude-code, lightrag, webhook, llm-judge, sdk. npm does not allow overwriting an already-published version.
Publish order matters because npm rejects a package version that depends on workspace package versions that do not exist yet:
@tagma/types@tagma/core@tagma/runtime-bun- Plugin packages:
@tagma/driver-codex,@tagma/driver-claude-code,@tagma/middleware-lightrag,@tagma/trigger-webhook,@tagma/completion-llm-judge @tagma/sdk
Because @tagma/sdk depends on @tagma/core, @tagma/runtime-bun, and @tagma/types, those packages must be published to npm before publishing an SDK version that references them.
3. Manual Publish
Use these only when the CI path is unavailable. Each script runs the required build steps and then bun publish.
bun run publish:types
bun run publish:core
bun run publish:runtime-bun
bun run publish:driver-codex
bun run publish:driver-claude-code
bun run publish:middleware-lightrag
bun run publish:trigger-webhook
bun run publish:completion-llm-judge
bun run publish:sdk
bun run publish:all
4. Dry Run
bun run publish:dry
tagma-editor and tagma-desktop live directly under apps/ in this monorepo. Desktop releases ship as installer artifacts via release-desktop.yml; see apps/electron/README.md. A normal clone contains the desktop sources; no extra initialization step is required.
Local edits to the desktop sources are ordinary monorepo changes: edit files under apps/editor/ and apps/electron/, then commit them from the repository root with the related package changes.
5. Update Web Release Summary
After a desktop release syncs to tagma-web, update the matching web archive
entry from the repository root:
bun run release:web-summary -- <version> --summary-file <summary-en.md> --summary-zh-file <summary-zh.md>
By default, the tool edits ../tagma-web/src/content/archive/<version>.md.
<version> accepts 0.6.24, v0.6.24, or desktop-v0.6.24, and the archive
entry must already exist. File input is preferred for multiline Markdown because
shells such as PowerShell treat backticks as escapes.
Common forms:
# English and Chinese multiline Markdown summaries from files
bun run release:web-summary -- 0.6.24 --summary-file summary.en.md --summary-zh-file summary.zh.md
# English-only one-line summary
bun run release:web-summary -- v0.6.24 --summary "Short release summary"
# Non-default tagma-web checkout
bun run release:web-summary -- desktop-v0.6.24 --summary-file summary.en.md --web-dir D:\work\tagma-web
--summary-zh-file and --summary-zh are optional. Use either --summary or
--summary-file, and either --summary-zh or --summary-zh-file, not both.
Dependency Principles
- No internal path imports - packages only import from public
@tagma/*package names. - No
latest- workspace packages useworkspace:*; third-party semver ranges are resolved by the committed rootbun.lockand CI usesbun install --frozen-lockfile. - Published tarballs exclude
src/- public packages ship builtdist/output;@tagma/sdkalso ships its Bun-onlyscripts/preinstall.jsguard. - Editor uses public API only - it consumes sdk/types via workspace links and never reaches into package
src/.
Tech Stack
- Runtime: Bun >= 1.3
- Types: TypeScript 5.8+
- Frontend: React 19 + Vite + Tailwind
- Server: Express 5 + Bun
- Desktop: Electron 42 + electron-builder (NSIS / AppImage / deb / rpm / tar.gz / dmg)
- Package manager: Bun workspaces