Skip to content

Instantly share code, notes, and snippets.

@roninjin10
Created May 22, 2026 16:54
Show Gist options
  • Select an option

  • Save roninjin10/ef82bbd952ff3818420819dddf6df861 to your computer and use it in GitHub Desktop.

Select an option

Save roninjin10/ef82bbd952ff3818420819dddf6df861 to your computer and use it in GitHub Desktop.
What we built

What We've Built

A concise but complete inventory of all work Will (fucory) has built

The three repos

Repo GitHub Layer Stack
plue (private) github.com/codeplaneapp/plue Code hosting + execution substrate: sandboxes, workspaces, agent sessions, git/jj protocol, billing, .jjhub workflows Go API + Rust jj-FFI + SolidJS UI + Postgres + gVisor / Freestyle VMs
smithers github.com/smithersai/smithers Declarative orchestration engine: workflows, scheduler, agent adapters, time-travel, gateway, observability TypeScript + Effect.io + SQLite + JSX-DSL
gui github.com/smithersai/gui Native control plane + FFI runtime + Python agent harness Swift macOS/iOS + Zig libsmithers + Python FastAPI

Naming note. jjhub was the original name; and has gone by plue / Smithers Cloud / Codeplane depending on context. The .jjhub/ folder convention in repos kept its name for compatibility.


1. The declarative orchestration layer — smithersai/smithers

The "Terraform for software factories" core. JSX-based workflow DSL on a custom Effect.io scheduler. Not Temporal — we wrote our own.

It's currently TypeScript only but we have made functional proof of concept showing how it's intermediate data structure could be extended to python and other languages.

Smithers has extremely high user satisfaction. Many users who try it convert to becoming power users and advocates

Workflow definition format

Workflows are TypeScript/JSX components with Zod-typed outputs. They work similar to React which hacks into the models reinforcement learning. Models today are already great at smithers:

smithers((ctx) => (
  <Workflow name="bugfix">
    <Sequence>
      <Task id="analyze" output={outputs.analyze} agent={analyzer}></Task>
      <Task id="fix"     output={outputs.fix}     agent={fixer}></Task>
    </Sequence>
  </Workflow>
))

~100 example workflows in examples/ (code-review-loop.jsx, debate.jsx, dependency-update.jsx, …). All five superstructures from the memo (PR Factory, Health Monitor, Spec Pipeline, Recruiting, Incident Response) are composable from the existing catalog today.

Node catalog (packages/components)

  • Control flow: <Sequence>, <Parallel>, <Branch>, <Ralph> (bounded loop), <TryCatchFinally>, <ContinueAsNew>, <Subflow>
  • Human-in-the-loop: <Approval> / <ApprovalGate>, <HumanTask>, <Signal>, <WaitForEvent>, <Timer>
  • Higher-order patterns: <ReviewLoop>, <MergeQueue>, <ClassifyAndRoute>, <Debate>, <DecisionTable>, <EscalationChain>, <GatherAndSynthesize>, <Kanban>, <Optimizer>, <Panel>, <Poller>, <Runbook>, <Saga>, <ScanFixVerify>, <Supervisor>, <Worktree>, <Sandbox>

Runtime — durable, crash-safe, hot-reloadable

  • packages/scheduler — pure decision function: (TaskState, outputs) → EngineDecision[]
  • packages/engine — Effect.io execution (@effect/workflow, @effect/cluster, @effect/sql-sqlite-bun)
  • packages/driver — consumes decisions, runs tasks, reports results
  • packages/db — SQLite via Drizzle: event log, task state, approval requests, alerts, dynamic per-workflow output tables

Agent abstraction = our BYOH (packages/agents)

  • BaseCliAgent wraps any CLI harness (Claude Code, Codex, …) the way k8s wraps containers
  • AI SDK adapters: Anthropic, OpenAI, Pi, Kimi via @ai-sdk/* = our BYOM
  • Capability registry declares tools/limits per agent
  • Auto-detects installed CLI agents from $PATH
  • packages/accounts manages multi-account Claude/Codex/Gemini subscriptions

Other primitives

  • Time-travel (packages/time-travel + packages/vcs) — snapshots, diffs, fork-from-checkpoint, replay, revert via jj
  • Gateway (packages/gateway + gateway-client + gateway-react) — typed RPC, auth scopes, OpenAPI defs, WebSocket event streams
  • Observability (packages/observability + apps/observability) — OpenTelemetry-native, Prometheus, OTLP, pre-built Grafana dashboards
  • Memory (packages/memory) — semantic recall, namespaced facts, vector-ready
  • Scorers (packages/scorers) — LLM judges, aggregation, persistence — substrate for auto-eval / self-improvement loops
  • MCP server (apps/cli/src/mcp/semantic-server.js) — exposes Smithers operations as MCP tools so Claude/Cursor/Codex can orchestrate Smithers itself

CLI (apps/cli, 50+ commands)

init / up / down / supervise / ps / logs / events / inspect / node / why / chat / chat-create / hijack / human / approve / deny / signal / fork / replay / revert / timetravel / retry-task / alerts / observe / graph / agent {add,list,test,doctor} / accounts {list,remove} / memory / schedule {add,list,rm,start} / openapi {preview,issue,revoke} / workflow {run,list,create,doctor}

The memo's "shell into a running agent" = smithers hijack + smithers signal + smithers chat. Already shipped.


2. The hosting + execution substrate — codeplaneapp/plue (private)

This is the production layer the memo treats as a black box ("compute is flexible — sandbox, pod, GPU, or VM"). We've built all of it: code hosting, CI workflows, agent sandboxes, cloud workspaces, billing, GitHub sync.

Binaries (cmd/)

  • server — Chi-based Go API (Postgres, OTEL, SSE)
  • ssh — gliderlabs git-over-SSH
  • repo-host — git proxy + jj-FFI via Rust (smithers-ffi)
  • runner — Postgres task queue (FOR UPDATE SKIP LOCKED) → gVisor sandbox manager
  • guest-agent — runs inside sandbox, vsock to host
  • ws-runner — Freestyle VM lifecycle for full workspaces
  • electric-proxy — ElectricSQL real-time sync bridge
  • smithers — the Go CLI

HTTP API (116 tables, grouped routes)

Group Examples
Auth Sign-in-with-Key (ECDSA), GitHub OAuth, WorkOS SSO, Auth0, OAuth2 server, SSE tickets
Repos /api/repos/{owner}/{repo} — metadata, contents, git trees/commits, jj changes/diffs
Landing requests jj-native stacked PRs — /landings/{n}, /diff, /conflicts, /reviews, /comments
Stacks & bookmarks jj active-stack management, protected bookmarks
Issues GitHub-compatible — issues, comments, reactions, dependencies, pinning, artifacts
Workflows /actions/runs/{id}, /workflows/runs/{id}/nodes/{nodeId}, cache/artifact APIs
Agents /agent/sessions/{id} — messages, streaming SSE, events
Workspaces Freestyle VM provisioning, /workspaces/{id}/ssh, snapshots, sessions
Orgs/teams members, teams, permissions
Billing Stripe — checkout, refresh, webhooks; tiers, entitlements, usage counters, credit ledger
Search full-text repo + issue search (Postgres FTS)
Integrations MCP registry (/api/integrations/mcp), AI skills (/api/integrations/skills), Linear sync
Webhooks GitHub App, Linear, Stripe, canary, user-registered repo webhooks (see §3)
Internal runner register/claim/heartbeat, task stream/complete, push events
Git smart HTTP /info/refs, /git-upload-pack, /git-receive-pack

Sandbox / runner architecture — the memo's "configurable compute"

  • gVisor sandboxes for ephemeral task execution (limited syscalls, vsock host comms)
  • Freestyle VMs for full cloud workspaces (SSH, snapshots, fork-for-parallel-exploration, suspend/resume)
  • Both share the agent-session abstraction

Infrastructure (infra/)

  • Helm charts (infra/helm/smithers, infra/helm/electric, cert-manager)
  • Terraform for GCP (Cloud SQL Postgres, GCS, GKE)
  • k6 load tests

Web UI (apps/ui)

SolidJS + Tailwind. Repo browser, issues, landing requests, workflow runs, agent chat, workspaces. SSE for real-time updates. Built-in Ghostty terminal. Plus docs, marketing, admin, github-sync, notion-sync.

This is purely a POC WIP. The webui is meant to work exactly as the mobile app. We also have an even more powerful desktop app inp rogress.


3. The .jjhub/ workflow system — GitHub Actions, but as JSX

This is what makes plue a factory substrate, not just a code host. Every repo can commit a .jjhub/workflows/*.tsx directory; plue discovers, schedules, and executes those workflows in sandboxes.

Workflow-as-code format

A .jjhub/workflows/ci.tsx looks like this (real example from our self-hosted CI):

import { Workflow, Task, Parallel, on } from "@smithers-ai/workflow";
import { $ } from "bun";

export default (
  <Workflow
    name="ci"
    triggers={[
      on.push({ bookmarks: ["main"], ignore: ["infra/**"] }),
      on.landingRequest.opened(),
      on.landingRequest.synchronize(),
      on.landingRequest.readyToLand(),
    ]}>
    <Parallel>
      <Task id="lint-go">{async () => { await $`golangci-lint run --timeout=5m`; }}</Task>
      <Task id="lint-rust"></Task>
      <Task id="lint-helm"></Task>
      <Task id="lint-ts"></Task>
    </Parallel>
    <Parallel>
      <Task id="test-go-unit"></Task>
      <Task id="test-go-integration"></Task>
    </Parallel>
  </Workflow>
);

The package — @smithers-ai/workflow in packages/workflow/ — re-exports Sequence, Parallel, Branch, Ralph from smithers-orchestrator and adds plue-specific Workflow and Task components plus the on.* trigger builder. It's the same engine as smithers — plue's runner instantiates smithers-orchestrator and calls runWorkflow() with SmithersCtx. The TSX in .jjhub/workflows is rendered to the Smithers workflow schema and executed by the same scheduler.

Trigger catalog (packages/workflow/src/triggers.ts)

Every constructor returns a TriggerDescriptor with a _type discriminator:

  • on.push({ bookmarks?, tags?, ignore? })
  • on.landingRequest.opened() | closed() | synchronize() | readyToLand() | landed()
  • on.release.published() | updated() | deleted() | released() | prereleased() (with optional tags)
  • on.issue.opened() | closed() | edited() | reopened() | labeled() | assigned()
  • on.issueComment.created() | edited() | deleted()
  • on.schedule(cron) — cron-based scheduling
  • on.manualDispatch(inputs?) — manual trigger with typed inputs
  • on.webhook(event) — generic event routing (anything plue receives or fires)
  • on.workflowRun({ workflows, types? }) — trigger on completion of another workflow
  • on.workflowArtifact({ workflows?, names? }) — trigger on artifact upload

<Task> props

id, output?, agent?, skipIf?, needsApproval?, timeoutMs?, retries?, continueOnFail?, label?, meta?, if?, cache?.

Plus first-class helpers: createWorkflowArtifactHelpers() (upload/download) and createWorkflowCacheHelpers() (save/restore — GitHub Actions cache equivalent).

Discovery + dispatch pipeline

  1. Discovery. When a repo is pushed or a workflow run is requested, plue parses .jjhub/workflows/*.tsx. collectRegisteredWorkflowTriggers(cfg) in internal/services/workflow_trigger_registry.go walks each workflow's triggers={…} prop.
  2. Persistence. Triggers are inserted into the workflow_triggers table: event_type (push, pull_request, pull_request_review, check_suite, check_run, stack_submit, schedule, manual), event_action (e.g. "opened", "synchronize", "published"), plus workflow_path, workflow_definition_id, repository_id, enabled.
  3. Matching. ListWorkflowTriggersByRepository(repositoryID) fetches all enabled triggers for fast event-time lookup.
  4. Scheduling. An incoming event (push, webhook, cron tick, manual dispatch) is matched against triggers and matching workflows are enqueued as workflow_runs.
  5. Execution. The runner pulls tasks via POST /internal/runners/{id}/claim (Postgres FOR UPDATE SKIP LOCKED), spins up a gVisor sandbox, and the guest-agent executes the rendered Smithers graph. Logs stream via SSE into workflow_logs; results land in workflow_steps / workflow_tasks.

Everything is observable in the GUI's JJHubWorkflowsView and via the /api/repos/{owner}/{repo}/actions/runs/{id} API.


4. Webhooks (inbound + outbound)

Inbound — what plue receives

All handlers live in internal/routes/ and internal/services/:

Endpoint Handler Verification What it does
POST /webhooks/github GitHubWebhookHandler HMAC-SHA256 (X-Hub-Signature-256) Enqueues github_webhook_jobs for async processing
POST /webhooks/linear LinearIntegrationHandler Linear SDK signature Syncs Linear issue state to plue issues / landing requests
POST /api/billing/webhook BillingHandler Stripe ConstructEvent() Updates subscription state, billing entitlements
POST /canary/webhook-receiver/{token} CanaryWebhookHandler HMAC-SHA256 token Receives canary deployment health checks

GitHub webhook flow (internal/services/github_webhook.go:141):

  1. HandleGitHubWebhook(deliveryID, eventType, signature, payload) verifies signature
  2. Filters supported events: push, pull_request, pull_request_review, check_suite, check_run, installation, installation_repositories
  3. Enqueues a row in github_webhook_jobs (delivery_id, event_type, action, installation_id, github_repository_id, payload)
  4. Handles installation events directly (upserts github_app_installations + github_app_installation_repositories)
  5. A worker polls github_webhook_jobs (status=pending), translates GitHub repo IDs to plue repo IDs via ListRepositoryIDsForGitHubWebhookJob(), then evaluates workflow_triggers → enqueues matching workflow_runs

That last step is how on.push(...) in a .jjhub/workflows/*.tsx actually fires.

Outbound — webhooks plue sends

Repo-owners can register custom webhooks per repo (GitHub-style "Webhooks" tab):

  • CRUD: POST/PATCH/DELETE /repos/:owner/:repo/hooks
  • Model: db.Webhookid, repository_id, url, secret, events[], is_active
  • Secrets encrypted at rest via webhookSecretCodec (AES wrapper)
  • Max 20 per repo
  • Subscribable events: push, pull_request, landing_request.opened, landing_request.closed, landing_request.synchronize, workflow_run.completed, etc. — same vocabulary as the trigger DSL

Delivery system (internal/webhook/):

  • Queue: webhook_deliveries table (webhook_id, event_type, payload, status, attempts, next_retry_at)
  • Worker (worker.go): PollQueue() claims due deliveries, sends HTTP POST with X-Smithers-Signature-256 HMAC
  • Retry policy: exponential backoff, terminal failure auto-disables the webhook
  • Test endpoint: POST /repos/:owner/:repo/hooks/:id/tests — enqueues immediate delivery with sample payload
  • Observability: every attempt logged with status, response_status, response_body, processed_at

This makes plue a two-way event hub: GitHub events flow in, plue events flow out, and .jjhub/workflows sit in the middle reacting to either.


5. The native control plane — smithersai/gui

Native desktop + mobile control plane plus an FFI runtime any other client could link.

Swift macOS app (~50K LOC, 100+ views)

Dashboard, Runs (live + inspect), Approvals, Changes/Diff, Issues, Workflows (JJHubWorkflowsView.swift), Agents, Frame Scrubber (time-travel UI), Chat (markdown segmentation + privacy redaction), embedded Ghostty terminal, SQL browser, dev telemetry, multi-workspace switcher, command palette, custom keybindings, browser surface for browser-tool output.

Onboarding, settings, devtools live inspector, repos, workflow runs, terminal (Ghostty VT renderer), chat, approvals, OAuth2 auth.

DevTools client

Smithers.Client.swift + DevToolsModels.swift + DevToolsStore.swift — routes through libsmithers FFI or HTTP gateway based on connectionTransport. Snapshot/delta streaming with sequence tracking, exponential-backoff reconnect, "ghost node" LRU for unmounted task nodes, stale-banner after 2 s disconnect, audit-row tracking for cross-run memory. Live ↔ Historical(frameNo) switching is built-in.

Zig core — libsmithers (libsmithers/, build.zig)

  • C ABI in smithers.h: smithers_core_t, sessions, event callbacks (STATE_CHANGED, AUTH_EXPIRED, RECONNECT, SHAPE_DELTA, WRITE_ACK, PTY_DATA, PTY_CLOSED), write() (pessimistic mutation with audit-row futures), shape_subscribe(), PTY attach/write/close
  • Modules: core/ (sessions, transport, cache, schema), core/electric/ (Electric protocol), core/wspty/ (WebSocket PTY), devtools/ (snapshot+stream client), terminal/ (PTY cell rendering, SGR), workflow/ (DAG parsing), persistence/, session/ (zmux daemon control)
  • Ghostty terminal via GhosttyKit.xcframework built from vendored submodule

Python agent backend (agent/, main.py)

  • FastAPI + Pydantic AI + MCP. create_agent_with_mcp() with extended thinking (50K budget), 64K max output
  • task_executor.pytask() single delegation, task_parallel() up to 10 concurrent
  • Agent types in registry.py: build / plan / explore / general, each with declared tool access
  • Tools: file I/O (read/edit/multiedit/patch), grep, LSP (hover/diag/defs/refs/symbols), PTY exec, browser automation (snapshot/click/type/scroll/extract/navigate), web fetch, task delegation
  • Git-based snapshot system (snapshot/snapshot.py) — bare repo at .agent/snapshots/, track() → tree SHA, restore(sha) → reset working tree

Go SDK + TUI (sdk/agent/, tui/)

Charmbracelet Bubbletea TUI as a fallback interface; SDK wraps the Smithers API.

Steering primitives at the UI layer

Slash commands (/run, /approve, /revert), command palette, frame scrubber for time-travel review, external-agent launcher (Smithers.ExternalAgent.swift — spawns claude / codex / gemini CLIs with session watcher).


How this maps to the memo

Memo primitive Where it lives today
Declarative workflow-as-code smithers JSX DSL + Zod outputs
GitHub-Actions-style repo workflows .jjhub/workflows/*.tsx in plue, dispatched by workflow_triggers table
Composable modules / npm-style registry Component catalog in packages/components; npm distribution exists, marketplace doesn't
BYOH (wrap harnesses like k8s wraps containers) packages/agents BaseCliAgent + capability registry
BYOM AI SDK adapters: Anthropic, OpenAI, Pi, Kimi + accounts mgmt
Triggers on.push / landingRequest.* / release.* / issue.* / schedule / manualDispatch / webhook / workflowRun / workflowArtifact
Inbound webhooks /webhooks/github, /webhooks/linear, /api/billing/webhook, canary — fan out to workflow triggers via github_webhook_jobs
Outbound webhooks Per-repo user-registered webhooks, signed HMAC, retry queue in webhook_deliveries, test endpoint
Decision gates / approvals <Approval>, <HumanTask>, durable timeouts, smithers approve/deny
Steering (shell-in, mid-run messages) smithers hijack / signal / chat; GUI command palette + slash commands
Time-travel & forking packages/time-travel + smithers fork/replay/timetravel/revert; GUI FrameScrubber
Observability / cost OTEL + Prometheus + Grafana in packages/observability; billing/usage in plue
Configurable compute gVisor sandboxes + Freestyle VMs in plue (cmd/{runner,ws-runner,guest-agent})
Self-hostable OSS core smithers + gui are self-contained and locally runnable; plue is the managed cloud
Managed cloud DX plue: hosted API, billing, workspaces, runner pool, GitHub App, custom webhooks
Real-time control plane Native macOS/iOS GUI + SolidJS web UI + Gateway WebSocket streams
Declarative policies Gap — exists as ad-hoc config, not a top-level primitive
Managed secrets / network allow-deny Repo/org secrets exist (repository_secrets, organization_secrets); network policy is a gap
Module marketplace MCP/skills registry endpoints exist (/api/integrations/{mcp,skills}); distribution layer is a gap

One-line summary. The engine, the substrate, and the control plane are all built. .jjhub/workflows/*.tsx already gives every repo a GitHub-Actions-equivalent that runs on the same Smithers scheduler as long-running agent workflows — there is no separation between "CI" and "agentic factory." What remains is the declarative policy layer, the module marketplace, and turning the substrate into a productized cloud — i.e. exactly the surface the memo argues is the next 18-month frontier.

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