Skip to content

feat!: rebuild Facility around persistent story workspaces - #289

Merged
adrian-lorenzo merged 10 commits into
mainfrom
feature/persistent-story-workspaces
Sep 4, 2026
Merged

feat!: rebuild Facility around persistent story workspaces#289
adrian-lorenzo merged 10 commits into
mainfrom
feature/persistent-story-workspaces

Conversation

@adrian-lorenzo

@adrian-lorenzo adrian-lorenzo commented Sep 2, 2026

Copy link
Copy Markdown
Member

Purpose

Facility 0.12 makes a persistent story workspace the unit of work. A story, its shared conversation, Git worktree, native Claude Code and Codex sessions, development services, previews, commits, and pull request now follow one lifecycle.

Compute can sleep or be replaced. The workspace stays available until a maintainer explicitly deletes it. Merging or archiving a story does not remove its worktree, local data, conversation, or engine sessions.

MCP is the primary control surface. The web UI remains supported and uses the same application services.

Workspace behavior

  • Starting the same GitHub issue or pull request in the same repository reuses its story workspace.
  • A workspace can clone every repository connected to the project, create branches and commits, push changes, and open or update pull requests.
  • Repository setup, start, readiness, browser test, and service declarations come from .facility.yml.
  • Docker and Docker Compose run inside the workspace without mounting the host Docker socket.
  • Declared services are available through authenticated, project-scoped preview URLs. HTTP and WebSocket traffic use the same access boundary.
  • Claude Code and Codex use native resumable sessions. Later turns continue in the same worktree with the shared conversation history.
  • Suspension, merge, archive, disabled schedules, failed turns, and compute replacement retain durable state.
  • Explicit deletion is authorized, isolated, and idempotent. It removes only the selected workspace.
  • Corrupt native sessions are retained for diagnosis. A maintainer can retry in the same worktree with a replacement session.

Agents as code

.agents/ is the source of agent configuration. Kickstart, the API, MCP, the scheduler, and the UI use the same strict parser, normalized representation, and content hash.

Kickstart installs six agents:

  • architect
  • builder
  • pr-reviewer
  • address-review
  • ci-doctor
  • security-audit

Each manifest declares its prompt, engine, model, enabled state, and manual, GitHub, or schedule triggers. Permission, sandbox, tool allowlist, and max_turns fields are rejected. Every agent receives full workspace access and the GitHub App's configured maintainer capability for the repositories connected to the project.

Agent changes made in the UI are proposed on a branch and pull request. Repeated requests are idempotent, later edits advance the open pull request without force-pushing, and stale branches are rejected.

Facility also inventories valid repository-owned skills under .agents/skills/**/SKILL.md and .claude/skills/**/SKILL.md. The Agents page, REST API, SDK, and facility_list_skills MCP tool expose their names, descriptions, paths, hashes, and source commit. Facility does not install or upgrade a separate catalog.

Scheduled agents remain part of the product. Manual, MCP, UI, GitHub, and scheduled work all enter the same turn dispatcher. A second message waits behind the active turn and is promoted after success, failure, cancellation, or stale-worker recovery.

Cost and budget controls

Cost analysis and budgeting stay in Facility without a separate model gateway or metering service.

  • Claude Code and Codex usage events are stored once per turn.
  • Provider-reported cost is preferred when available. The Facility price book is the fallback.
  • Usage remains visible when an engine returns a failed result with accounting data.
  • Each project can set a monthly UTC budget and warning threshold through MCP, API, or the Insights page.
  • Budget enforcement runs before credentials are issued, the development environment is prepared, or the provider is called.
  • A call admitted below the limit is allowed to finish and is accounted afterwards. Later turns are blocked once the limit is reached.
  • An unpriced model is blocked only when budget enforcement is enabled. This avoids presenting an unenforceable limit as safe.

Observability and delivery analytics

Operational monitoring, product analytics, and audit history stay in the existing API, worker, and PostgreSQL database.

The Insights surface reports:

  • turn outcomes and success rate
  • input, output, and cache token use
  • attributed cost and unpriced turns
  • budget state and remaining amount
  • workspace states and retained workspaces
  • open attention items
  • GitHub webhook and CI health
  • activity grouped by agent and model
  • daily usage and delivery trends
  • merged pull requests, observed first-pass CI rate, and pull request lead time
  • recent persisted audit events

AWS deployments also enable ECS Container Insights, RDS Performance Insights, PostgreSQL logs, and service log groups in CloudWatch.

GitHub mirror and pipeline

Facility keeps a project-scoped mirror of GitHub issues, branches, pull requests, reviews, checks, and CI state.

  • Signed webhooks update the mirror before agent triggers run.
  • A worker reconciles connected repositories every ten minutes to recover missed webhooks.
  • Maintainers can request an immediate reconciliation through MCP, API, or the Pipeline page.
  • Commit statuses and check runs are combined into one CI state.
  • CI events update a pull request only when the head SHA is current.
  • Stories, issues, branches, pull requests, reviews, and checks are linked per repository, including projects with several repositories.
  • GitHub facts are linked to an exact Facility turn when their head SHA matches that turn's recorded final SHA. Other matching changes remain story-level external evidence.
  • The Pipeline page presents Backlog, Planning, Building, Validating, In review, and Shipped stages.

MCP, API, SDK, and UI

The MCP server exposes 20 tools. The original workspace and conversation tools remain, with project skill inventory plus costs, budgets, observability, the delivery pipeline, and GitHub reconciliation.

The REST API and generated TypeScript SDK expose the same capabilities. The web UI adds Pipeline and Insights while keeping project setup, agent and skill inspection, stories, conversation history, workspace controls, previews, attention handling, archive, restore, and deletion.

Each turn records agent, engine, model, session, workspace, branch, and initial Git SHA before engine execution. Final SHA, commits, changed files, and dirty state are captured when it settles, including failure and cancellation paths. GitHub branch, pull request, review, and check facts join those records in one ordered story timeline in the UI and facility_get_story. Ten-minute reconciliation discovers changes made outside Facility without falsely attributing them to an agent turn.

Security model

Agents are trusted repository maintainers inside an isolated workspace. Facility does not maintain receipts, approval workflows, delivery brokers, or per-agent permission profiles.

Authentication, project membership, tenant isolation, webhook signatures, secret handling, preview authorization, branch protection, and control-plane isolation remain enforced. Installation tokens are short-lived. They keep the GitHub App's configured maintainer permissions and are limited to repositories connected to the active project.

Project repositories can request only explicitly configured, project-namespaced environment values. They cannot read arbitrary Facility process environment variables. Preview handoffs are single-use, expire, and are revoked when a workspace is suspended or deleted.

Reference deployment

The new Terraform module keeps the durable control plane in AWS and all story workspaces in Vercel Sandbox.

AWS provides:

  • an HTTPS Application Load Balancer
  • ECS services for API, worker, and web
  • RDS PostgreSQL 16 with backups, encryption, deletion protection, and Performance Insights
  • ECR repositories for API and web images
  • Secrets Manager and KMS
  • CloudWatch logs and ECS Container Insights
  • a one-off migration task

Vercel provides the isolated development workspace, retained snapshots, Docker and Compose execution, and exposed service endpoints. AWS does not provision workspace tasks, CodeBuild sandboxes, preview containers, or a model gateway.

0.12 cutover

The package set and generated SDK are versioned at 0.12.0. The legacy run, receipt, HITL, proposal, model gateway, agent registry, and separate preview paths no longer ship. Their required cost, budget, monitoring, analytics, audit, scheduling, mirror, and pipeline capabilities are implemented in the smaller 0.12 control plane.

0.12 uses a clean database schema. The migration command detects a 0.11 runs table and exits before creating a migration ledger or changing schema objects. The upgrade guide documents backup, export, clean installation, and rollback to an untouched 0.11 database.

Persistent storage is an operator responsibility. Local conformance tests use deterministic export and restore. Hosted installations must retain Vercel workspace snapshots and RDS backups according to their policy.

Acceptance evidence

The following local checks passed on commit ccb2487:

  • pnpm verify completed successfully.
    • Biome checked 217 files.
    • Typecheck completed 14 of 14 tasks.
    • The clean build completed 8 of 8 tasks with the Turbo cache disabled.
    • Disposable databases were recreated and all three 0.12 migrations were applied from scratch.
    • The script suite passed 114 tests.
    • Package suites passed 9 agent tests, 10 core tests, 10 SDK tests, 32 web tests, 14 MCP tests, and 10 documentation tests.
    • Every API suite selected by the critical test runner passed without skips.
    • Unused-component detection found no removed package, import, environment, or deployment references.
    • The pinned-action and Markdown-link guards passed.
    • The dependency audit reported only the two high-severity findings already ignored by repository policy.
  • Five focused API files passed 28 tests for skill discovery, turn Git capture, the unified timeline, GitHub webhook evidence, periodic reconciliation, and tenant isolation.
  • Database tests passed 7 tests, including cross-tenant rejection for project skills and story evidence.
  • pnpm migrations:check passed.
  • The current runner image built locally as facility-runner:dev.
  • The Docker runtime E2E passed without skips in 43.63 seconds. It exercised nested Compose, authenticated preview, Chromium, cancellation, compute replacement, retained worktree and native session state, backup, and restore.
  • The Facility 0.12 journey passed through MCP and the web-facing API against an isolated PostgreSQL database.

GitHub CI for this commit is reported by the pull request checks. No live repository or hosted environment was changed during local acceptance. This pull request remains a draft. It has not been merged, and no package or container image has been published.

Release gates still open

These checks need private infrastructure or elapsed time and remain open:

  • deploy the candidate to a protected pre-release environment
  • run real hosted Claude Code and Codex sessions and resume them after compute replacement
  • run the reference journey with a non-production GitHub App installation, including branch push, pull request update, GitHub triggers, and scheduled triggers
  • open an authenticated remote preview from a second computer
  • complete the 14-day retention soak

The proposal is in progress and assigned to @adrian-lorenzo. The PR should remain a draft until these gates and the owner's review are complete.

Related to #272
Related to #273
Related to #274
Related to #275
Related to #276
Related to #277
Related to #278
Related to #279
Related to #280
Related to #281
Related to #282
Related to #283
Related to #284

@adrian-lorenzo adrian-lorenzo self-assigned this Sep 2, 2026
Make stories the durable unit of work, configure all agents through .agents, expose the workflow through MCP and the UI, and run Claude Code or Codex with full workspace and GitHub installation access.

BREAKING CHANGE: Facility 0.12 replaces the 0.11 run, receipt, approval, budget, delivery, and separate-preview model with persistent story workspaces and a new database schema.
@adrian-lorenzo
adrian-lorenzo force-pushed the feature/persistent-story-workspaces branch from 7eb262a to 181f1f3 Compare September 2, 2026 18:27
@adrian-lorenzo
adrian-lorenzo marked this pull request as draft September 2, 2026 18:49
@manuelgm0518

Copy link
Copy Markdown

Durable workspaces look directionally strong. Before this closes #284, could the PR include a criterion-by-criterion evidence table distinguishing automated CI, completed manual validation, and still-pending gates—especially the 14-day soak and live-engine pilots?

I’d also like to understand the threat model for giving GitHub-triggered reviewers and scheduled agents the same maintainer capability as builders when their inputs are explicitly untrusted.

@BrunoInz

BrunoInz commented Sep 2, 2026

Copy link
Copy Markdown

One thing I noticed while reading the 0.12 branch, in case it helps before this lands.

The workspace GitHub token is minted for the whole installation, not for the project's repositories.

  • services/api/src/github/client.tscreateGithubMaintainerTokenFactory calls POST /app/installations/{installation_id}/access_tokens with no repositories field (the comment says so explicitly: "No repository or permission override is sent"). On main the same call passes repositories: [repo].
  • services/api/src/github/workspace-credentials.ts — that token becomes GH_TOKEN / GITHUB_TOKEN in the turn environment. The credential helper (runner/facility-git-credential.mjs) only releases a token for a configured repo path, but that narrows git-over-HTTP only; gh is in the runner image and the turn prompt tells the agent it has GitHub maintainer access.
  • The test in services/api/test/agent-catalog-and-github-credentials.integration.test.ts asserts this behaviour by name ("issues one un-narrowed installation token to every configured repository").

Consequence: when two projects share an App installation, an agent in project A holds a maintainer-capable token for project B's repositories (and for any other repository the installation covers). That seems at odds with the boundary the epic keeps: #279 says "a request for another tenant, project, installation, or repository is denied", and the new security.md in this PR says "short-lived GitHub credentials scoped to configured project repositories".

Suggested fix: pass the project's repositories for that installation in the token request (repositories: [...]), grouped per installation as the broker already does. It stays uniform across agents (no per-agent permission calculation, which the epic bans) and only narrows to the project boundary. I'd add a case to the existing integration test asserting the repositories argument the factory receives.

Happy to open a PR for it if you'd take one.

@EaglewithGlasses

Copy link
Copy Markdown

Thanks for this massive rebuild – the persistent workspace concept is a great evolution. I am new to this project, and going through the changes to understand the data model, and I have a quick question about the removal of the old runs, receipts, and proposals tables.

The PR description says these are removed, but I don’t see a migration script that drops or archives them. For existing self‑hosted instances (even in 0.x), what’s the expected upgrade path? Should users manually back up and drop those tables, or is the plan to keep them around until a later migration?

I’m happy to help draft a migration script if we decide to archive the old data before removal. Let me know what you’d prefer.

@adrian-lorenzo

Copy link
Copy Markdown
Member Author

Documentation follow-up in e5ea723:

  • Restored complete user, operator, reference, and contributor documentation while keeping the 0.12 information architecture focused.
  • Added exact references for project and agent manifests, workspace lifecycle, API resource families, permissions, retention, operations, hardening, costs, observability, GitHub synchronization, AWS deployment, and troubleshooting.
  • Added contributor guides for architecture, testing, and documentation, plus a runner guide and clearer local-development paths.
  • Added documentation contract tests so future simplification cannot silently remove essential user, operator, or contributor coverage.

Validation on the current head:

  • Documentation contract tests: 8/8 passed.
  • Docusaurus production build: passed.
  • Markdown link guard and repository guards: passed.
  • Full release-shaped verification: passed.
  • Minimum supported Node.js verification: passed.
  • Clean self-host stack build: passed.
  • Docker-backed persistent workspace E2E: passed.

The first audit attempt timed out against the npm advisories service in both local and CI runs. The unchanged CI retry passed. The PR remains a draft; no package or image publication ran.

@adrian-lorenzo

adrian-lorenzo commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

@manuelgm0518 Thanks for raising this. These are useful release-confidence checks, but Facility is still experimental and evolving within the 0.x series. We have decided not to hold this merge for the 14-day soak or the live-engine pilots. The automated end-to-end journey passes, and we will continue the soak and hosted validation after the merge while iterating towards a stable release.

The maintainer-access model is intentional. GitHub-triggered and scheduled agents receive the same project capability as interactive agents. Inputs are treated as untrusted, credentials are short-lived and restricted to the repositories connected to the project, and branch protection, required CI, and human review remain the merge boundary.

This is a breaking release with a documented upgrade path rather than an in-place migration. Existing users can remain on 0.11 until they are ready to back up their installation and start 0.12 with a separate, empty database.

@adrian-lorenzo

adrian-lorenzo commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

@BrunoInz Thanks for catching this. You were right, and it has now been fixed.

Installation tokens are minted with the explicit repository list connected to the project, grouped by installation. Agents still receive the same maintainer-level permissions, but the token cannot reach other repositories covered by the GitHub App installation.

We also added regression coverage for the token request and for denying credentials to repositories outside the configured project.

@adrian-lorenzo

adrian-lorenzo commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

@EaglewithGlasses Thanks for raising this. The upgrade behavior is now implemented and documented.

Facility 0.12 uses a clean database boundary. It does not drop, archive, or modify the 0.11 tables. The upgrade path is to back up the existing installation, keep the 0.11 database available for rollback, and start 0.12 against a separate, empty database.

The migration command now detects a 0.11 database and refuses to continue before creating migration metadata or changing any schema objects. This behavior is covered by an integration test. Existing users can remain on 0.11 until they are ready to move to the new model.

@adrian-lorenzo
adrian-lorenzo marked this pull request as ready for review September 4, 2026 12:11
@adrian-lorenzo
adrian-lorenzo merged commit 3e3e998 into main Sep 4, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants