Existing substrate — what App Works builds on, and what is missing
Status: Reference · Created: 2026-09-17 · Verified against: develop @ 873274c9f (2026-09-17; previously e5f43f44d, before that ee45946e5)
Audience: anyone sizing or implementing an App Works epic
Re-verification 2026-09-17 (
a655b53ca→ee45946e5). Every repository path cited as existing across the program was checked by script againstdevelop@ee45946e5, along with the symbols cited next to those paths and the line numbers in the plans. Nothing the program relies on was removed or renamed.developgained AW-23 (Agent identity and brake) and AW-24 P1 (safety rails). The agent git tool defects APW-08 P0 fixes are still there unchanged; theAGENT_GIT_FACADEprovider only moved to ~lines 597–749 ofapps/api/src/agents/agents.module.ts. Five things are new, and the affected plans now say so. (1) Every Agent run passes a run admission chain: global stop flag → Agent brake → Work → organization → credits (APW-04, APW-08). (2) Every tool call passes a safety gate, andcommitToRepo/openPullRequest/ deploy count aspublish.external, with default rungask(APW-04, APW-08). (3) Approval proposals fold in the trust-ladder rung, andapproveAllcounts irreversible types asexcluded(APW-09). (4)AuthenticatedUser.authMethodalready exists as'session' | 'api-key', so APW-12 appends a value and does not add the field (APW-11, APW-12). (5) The newest migration is1791240000000-AddSafetyRailsCore.ts, still below every1792…block. Citations fixed in this pass (all wrong or vague when authored, not moved bydevelop): a...placeholder path, two shorthand filenames, paths for three evidence entries that named only a class,K8sApiService→KubernetesApiService(APW-07), theEVER_WORKS_DOMAINsource (APW-11) andevaluateAndRun's file (APW-08). APW-10 now has a naming note that separates its quarantine from the platform stop flag and the AW-23/AW-24 pauses. Re-checked one5f43f44d(AW-22 workspace backup, a schedules flat-list fix and a job-runtime audit fix): no cited path moved and no cited symbol was removed, the newest migration is still1791240000000-AddSafetyRailsCore.ts, APW-02's dispatcher arity now starts from 14 instead of 13, and every table an epic adds must now be classified for the workspace backup (Resolution R-25; row in §1).
Re-verification 2026-09-17 (
e5f43f44d→873274c9f, 21 commits). Re-checked every path and symbol the program relies on that these commits touch. Nothing the program relies on was removed or renamed, and the newest migration is still1791240000000-AddSafetyRailsCore.ts, so the1792…block is intact. Three things changed and the affected rows below now say so. (1) Fleet runs report the containment they actually got. A run's node-side record is normalised bynormalizeFleetAgentTaskContainment(packages/contracts/src/fleet/fleet-jobs.types.ts:1301, shape at:1245, downgrade list at:1224) and read byapps/api/src/fleet/fleet-agent-task-reconciler.service.ts; the operator's home directory is denied to the model step throughapps/node/src/core/model-execution/isolated-home.ts. A run can therefore be less contained than the design intends, and the record says so — APW-04 and APW-08 admission must read it rather than assume containment (see the row in §3 and Resolution R-33). (2) Clone URLs are validated before git sees them.isRemoteCloneUrl(packages/contracts/src/fleet/fleet-task-workspace.types.ts:239) allow-lists token-freehttps,httpandsshremotes and refuses option-shaped and transport-helper URLs; both workspace plugins call it (packages/plugins/local-workspace/src/local-workspace.plugin.ts,packages/plugins/sandbox-workspace/src/sandbox-workspace.plugin.ts). Plainhttp/httpsstay allowed, so the PR lane's fake GitHub on a loopback address still mounts. (3) Two acceptance-checks additions (apps/node/src/core/executors/acceptance-checks.ts) and a runtime change (apps/node/src/core/runtime.ts) — neither moves a path this program cites.
Standing rule (inherited from Agent Workspace). A "we don't have this" claim decays; a "we already have this" claim does not. Before building anything listed as missing below, search for it first. Every row names the file it rests on; line numbers are indicative and drift.
The headline: roughly half of the owner's loop already ships. The fork API call, server-side Kubernetes apply, a user-supplied kubeconfig, managed subdomains, custom domains, a per-Work Postgres provisioner, the Task → isolated workspace → checks → PR → merge-policy loop, the Fleet, the chat tool registry and the runtime-loaded Blueprint catalog are all real. What is missing is concentrated in: creating a Work from an arbitrary URL, understanding how to run arbitrary software, building it, running more than one stateless container, schema-driven env and dependencies, following upstream, and a hosting tier that is safe for user-controlled code.
1. Works, kinds and creation
| Capability | State on develop | Evidence |
|---|---|---|
| Work kinds + capability matrix | Ships. USER_SELECTABLE_WORK_KINDS (website, landing-page, blog, directory, awesome-repo, repo), WORK_KINDS adds company, campaign, default. work.kind is varchar(32) modelled as an open string union so a new kind can ship server-first. Capabilities are a per-kind hide-list consumed by API, agent and web (tabs, metrics). | packages/contracts/src/domain/work-kind.ts, packages/contracts/src/domain/work-capabilities.ts, docs/features/work-kinds.md |
Repository Work (repo, EW-766) | Ships — and is the closest precedent. GitHub-only URL parser; verifies the caller's own access (hasRepositoryAccess) before any side effect; 409 if another account already wraps the repository; persists sourceRepository.relatedRepositories.data, syncIntervalMinutes: 0; skips template, deploy quota, managed-git provisioning. One shared guard refuses every generator/deploy/write path. No fork, no build, no deploy — by design. | packages/agent/src/works/repository-work-source.ts, packages/agent/src/works/repository-work-guard.ts, packages/agent/src/services/work-lifecycle.service.ts (createWork repo branch, resolveRepositoryWorkSource), docs/internal/feat-repo-work-kind-notes.md |
| Kind-aware create UI | Ships. Kind chips on /new and /works/new; RepositoryWorkForm (URL → derived name/slug); the Repository chip routes the composer text to /works/new?mode=manual&kind=repo&prompt=…. The createWork server action requires a connected personal git provider for repo. | apps/web/src/components/works/RepositoryWorkForm.tsx, apps/web/src/components/new/NewPageClient.tsx, apps/web/src/app/[locale]/(dashboard)/works/new/new-work-client.tsx, apps/web/src/app/actions/dashboard/works.ts |
| Company / Campaign kinds | Ships. Minted by dedicated flows with deployProvider: null — the precedent for "a kind with no deploy by default". | WorkLifecycleService.createCompanyWork |
| Work Import | Ships. Arbitrary GitHub/GitLab/Bitbucket URL; modes data_repo, awesome_readme, link_existing. Directory-generation shaped; link_existing needs write access to that exact repository; no fork step. | docs/features/work-import.md, SourceRepoAnalyzerService (packages/agent/src/import/source-repo-analyzer.service.ts), WorkImportService (packages/agent/src/services/work-import.service.ts), packages/contracts/src/api/work/import-source.dto.ts |
.works/works.yml v2 kind specs | Ships. spec is discriminated by kind in KIND_SPEC_SCHEMAS; repo has source.{repo,branch}, tasks.{base_branch,checks} (checks bounded, documented as a trust boundary). Unknown kinds pass with a warning. tasks.checks IS read and executed today — repository-declared commands: readFleetRepoDeclaredCommands (task-workspace.service.ts:543) → parseRepoDeclaredCommands(spec) (:618) → admitRepoDeclaredCommands (:619), gated on the Work's repoDeclaredCommands.mode === 'allowlist' (:556, default 'off'), merged into the Fleet run plan at fleet-agent-task-planner.service.ts:589-590. Only tasks.base_branch is unread. Treat the block as a live trust boundary — its own module docblock is a "WHAT THE ALLOW-LIST DOES NOT BOUND" warning. | packages/agent/src/works-config/schema/works-config.schema.ts, docs/agent-services/works-yml-schema.md, docs/features/works-config.md |
| Repositories registry | Ships. Account-level repo_connections, credential pointers, seed .env files, Agent attachments. Attachment is advisory for the sandbox/local workspace providers (no executor checks an attached repository out yet). | packages/agent/src/services/repo-registry.service.ts, docs/features/repositories.md, docs/internal/feat-repo-registry-notes.md |
| Workspace backup (AW-22) | Ships (added after authoring). Owner-only dated .zip of one workspace in 15 sections plus a manifest (/api/account/backups, migration 1791220000000-CreateWorkspaceBackups.ts). Coverage is one table, BACKUP_DOMAIN_SPECS; BACKUP_DROPPED_ENTITIES and the { wasSet } maps decide what never leaves. A secret-shaped column with no rule fails a test, but a table in no section is silently absent — hence R-25. | packages/agent/src/account-transfer/backup/collectors/domain-specs.ts, collectors.spec.ts, packages/agent/src/account-transfer/backup/redaction.ts, apps/api/src/account/workspace-backup.controller.ts, docs/features/workspace-backup.md |
2. Templates, Blueprints and catalogs
| Capability | State on develop | Evidence |
|---|---|---|
| Work Blueprints catalog | Ships. manifest.json in the public ever-works/works repo, tokenless raw read with authenticated fallback, 1 h cache (30 s on failure), sanitized rows, public GET /api/work-templates?chipType=…, degrades to a built-in list. Template repos must match ^ever-works/[a-z0-9-]+$ (SSRF containment). The pattern to copy for the Apps catalog. | apps/api/src/works/works-template-catalog.service.ts, apps/api/src/works/work-templates.controller.ts, docs/features/work-blueprints.md |
| Work Templates (fork-first) | Ships. Fork a starter repository into the user's account/org with an owner picker; POST /api/templates/fork, POST /api/templates/custom accepts any GitHub URL as a catalog row. Forking is gated to sourceType === 'built_in'. | packages/agent/src/template-catalog/template-catalog.service.ts (forkTemplateForUser), apps/web/src/components/templates/CreateCustomTemplateDialog.tsx, docs/features/work-templates.md |
| Runtime catalogs (ADR-014) | Ships. ever-works/works, agents, orgs, skills, missions (+ placeholders tasks, ideas). Catalog content never lives in platform code. | GitHub org ever-works; docs/features/agents-catalog.md, docs/features/skills-catalog.md, docs/features/mission-templates.md |
3. Git provider, forks and pull requests
| Capability | State on develop | Evidence |
|---|---|---|
| Fork a repository | Ships, narrowly used. forkRepository?(owner, repo, {name, organization, defaultBranchOnly}) → POST /forks, then polls repos.get 24×5 s (blocking ~2 min), null on timeout. Looks for an existing fork only when name is passed. hasForkRelationship compares parent only. | packages/plugin/src/contracts/capabilities/git-provider.interface.ts, packages/plugins/github/src/github-api.service.ts |
| Repository metadata | Ships. getRepository returns isFork, parent, permissions — not source (root), allow_forking, archived. | same |
| Sync a fork with upstream | Missing. No merge-upstream call. WebsiteUpdateService.updateFork returns true without syncing (dead path); template "sync" is clone → swap remote → push. | packages/agent/src/generators/website-generator/website-update.service.ts |
| Ahead/behind divergence | Missing (compare-by-basehead exists as getCompareDiff, unused for this). | github-api.service.ts |
| Cross-repository pull requests | Missing. createPullRequest passes head through but maps the result to head: data.head.ref, dropping the head owner; no head_repo / maintainer_can_modify. | github-api.service.ts |
| Webhook installation | Missing. Inbound GitHub events (pull_request, push, check_run/suite, workflow_run, installation) are handled at POST /api/ingest/github/events, but nothing installs a webhook on a user repository. | apps/api/src/ingest/github/github-events.controller.ts, github-check-intake.service.ts |
| Actions secrets / workflows | Ships. Set secrets/variables, list/enable/disable workflows, dispatchWorkflow. | packages/plugins/github/src/github-actions.service.ts |
| OAuth scopes | Ships. Plugin OAuth requests repo, workflow, read:org, write:repo_hook, delete_repo, project, user scopes; the facade only asserts repo. | packages/plugin/src/common/github.scopes.ts, packages/plugins/github/src/github.connection-scopes.ts, packages/agent/src/facades/git.facade.ts |
| Token resolution | Ships. Explicit token → platform customer-org PAT when storage is managed → GitHub App installation token (sourceRepository.auth.mode) → user's OAuth account → plugin-settings PAT. | git.facade.ts (resolvePluginAndToken) |
| Local checkouts (isomorphic-git) | Ships, with two hazards. (1) Checkout directory is tmpdir/ever-works-repos/<slug(owner-repo)> — lower-cased with the separator lost, so a-b/c and a/b-c collide. (2) A NotFound/"empty" clone silently falls back to git init + remote — dangerous right after an asynchronous fork. No depth, no LFS; runs on the event loop. | packages/plugin/src/git/git-operations.ts |
| Task workspaces (shell git) | Ships. Sandbox and local worktree providers use shell git with --depth 1 default and per-operation credential injection. | packages/plugins/sandbox-workspace/src/sandbox-workspace.plugin.ts, packages/plugins/local-workspace/src/local-workspace.plugin.ts |
| Agent git tools | Appear broken on develop (to verify with a failing test first). commitToRepo passes providerId: '' (the ?? fallback keeps '', then "providerId is required"), ignores branch; openPullRequest passes owner: '', repo: ''. Both hard-code github. Re-verified unchanged on ee45946e5; since AW-24 both tools are classified publish.external and pass the safety gate in AgentRunService.invokeTool before the adapter runs. | apps/api/src/agents/agents.module.ts (AGENT_GIT_FACADE provider ~597–749), packages/agent/src/safety/action-category.ts |
| Fleet push credential | Ships. GitHub App installation token narrowed to repository ids with contents: write only — cannot change workflow files or open PRs by itself. | apps/api/src/fleet/fleet-push-credential.service.ts |
| Fleet run containment (added 2026-09-17) | Ships, and is narrower than it sounds. A run reports what containment it actually got: FleetAgentTaskContainment (fleet-jobs.types.ts:1245), its bounded downgrade list (:1224), FLEET_AGENT_TASK_EXECUTION_PATHS = ['hardened','ordinary'] (:1207), coerced by normalizeFleetAgentTaskContainment (:1301) and normalised into the run by apps/api/src/fleet/fleet-agent-task-reconciler.service.ts:959. The isolated home (apps/node/src/core/model-execution/isolated-home.ts) is environment construction only — no filesystem boundary and no egress control — and the ordinary runner keeps or back-fills HOME/USERPROFILE/APPDATA, so Fleet setup steps and App checks run with the machine's real home directory and toolchain. App Work run admission must read this record (Resolution R-33) rather than assume containment. | packages/contracts/src/fleet/fleet-jobs.types.ts, apps/api/src/fleet/fleet-agent-task-reconciler.service.ts, apps/node/src/core/model-execution/isolated-home.ts |
| Workspace clone-URL guards (added 2026-09-17) | Ships. Both workspace plugins refuse a non-remote clone URL: isRemoteCloneUrl (packages/contracts/src/fleet/fleet-task-workspace.types.ts:239) allows token-free http, https and ssh (including the user@host: scp form) and rejects option-shaped (-…), transport-helper (helper::) and control-character forms; assertRemoteCloneUrl enforces it in local-workspace.plugin.ts and sandbox-workspace.plugin.ts. Plain http/https stay allowed, so the PR lane's fake GitHub on a loopback address still mounts. | packages/contracts/src/fleet/fleet-task-workspace.types.ts, packages/plugins/local-workspace/src/local-workspace.plugin.ts, packages/plugins/sandbox-workspace/src/sandbox-workspace.plugin.ts |
4. Build, deploy, hosting
| Capability | State on develop | Evidence |
|---|---|---|
| Deployment plugins | Ships. vercel and k8s implement IDeploymentPlugin; DeployFacadeService resolves plugin + token + settings per Work; DeployService.deploy orchestrates. | packages/plugins/k8s/src/k8s.plugin.ts, packages/plugins/vercel/src/vercel.plugin.ts, apps/api/src/plugins-capabilities/deploy/deploy.service.ts |
| Two deploy paths | Ships. (a) Workflow dispatch: secrets pushed to the Work's website repository, which builds its own image in GitHub Actions and deploys. (b) Server-side: for platform-managed clusters the API calls KubernetesPlugin.deploy() directly, because CI runners cannot reach those clusters. | deploy.service.ts (deployServerSideManaged, workflow dispatch helpers) |
| Manifest rendering | Ships, single-container. Deployment + Service + Ingress + pull Secret for an image assumed to exist; per-tier memory floors; env from a <slug>-runtime-env Secret. No Jobs, CronJobs, multi-component, probes-from-spec, volumes or dependencies; not designed for untrusted code. | packages/plugins/k8s/src/manifest.renderer.ts |
| Generic build of arbitrary repos | Missing. No Dockerfile detection/generation, buildpacks, compose parsing. Today's builds exist only because the platform owns each template's Dockerfile and build workflow. | repository-wide search |
| Cluster-source matrix / BYO kubeconfig | Ships. k8s-works-shared (default), k8s-works (admin-only), custom-kubeconfig (user-supplied, encrypted x-secret), validated server-side. | apps/api/src/plugins-capabilities/deploy/cluster-source-matrix.ts, docs/specs/features/k8s-cluster-source-matrix/spec.md, packages/agent/src/facades/deployment-context.resolver.ts |
| Managed subdomains | Ships. SubdomainAllocator + cloudflare-dns plugin; managed hosting env-gated with a per-user cap of 3 Works. | packages/agent/src/ever-works-providers/subdomain-allocator.service.ts, docs/features/managed-hosting.md, EverWorksDeployQuotaService (packages/agent/src/ever-works-providers/ever-works-deploy-quota.service.ts) |
| Custom domains | Ships. Add/verify/remove; verification checks the record resolves to the cluster's ingress; hosts merged into the Ingress. | docs/features/custom-domains.md, deploy.service.ts (mergeCustomDomainHosts), packages/plugins/k8s/src/domain.handler.ts |
| Per-Work Postgres | Ships. One database + one role per Work, idempotent DDL, on a shared server or a user-supplied server. No Redis, no object storage. Built for platform-generated Works — must not be reused for untrusted apps as-is (README D8). | packages/agent/src/ever-works-providers/ever-works-db-provision.service.ts |
| Runtime env for deployed sites | Ships, allow-listed. WORK_RUNTIME_ENV_ALLOWED_KEYS is a fixed Stripe-shaped list; anything else is 400. Platform-minted keys assembled per deploy. | packages/agent/src/services/work-runtime-env.constants.ts, deploy.service.ts (collectServerSideRuntimeEnv), docs/runbooks/WORK_RUNTIME_ENV.md |
| Deployment verification | Ships. DeploymentVerifierService polls status and surfaces it on the Deploy tab and in Activity. DeploymentEnvironment is production / preview only. | apps/api/src/plugins-capabilities/deploy/tasks/deployment-verifier.service.ts, packages/agent/src/entities/work-deployment.entity.ts |
| "Environments" feature | Ships — but it is agent sandbox runtime recipes, not dev/stage/prod deploy environments. Do not reuse the word. | docs/features/environments.md |
5. Agents, chat and the evolve loop
| Capability | State on develop | Evidence |
|---|---|---|
| Platform chat tools | Ships. ~400 tools (generated + hand-written) incl. create Work, create/run Task, Missions; destructive tools require confirmation. | apps/web/src/lib/ai/tools/index.ts, work.tools.ts, missions.tools.ts, docs/features/platform-chat.md |
| Task → Run → PR | Ships, kind-agnostic. Run resolves an Agent; worktree-per-Task via the workspace capability; pipeline plugins (claude-code, codex, opencode, claude-managed-agent, gemini, agent-pipeline); finalize pushes, simulates the merge, opens a same-repository PR. taskIsolationTargetRepo is declared but not consumed — the triple work-output/data/provider exists on the entity (work.entity.ts:426) and is sanitised on import (account-import.service.ts:752,842), but nothing resolves it: task-workspace.service.ts:219-220 hard-codes work.getRepoOwner()/work.getDataRepo(), and the web write path accepts a different pair (z.enum(['work-output','linked']), apps/web/src/app/actions/dashboard/works.ts:1515). Repo targeting is therefore not configurable today — do not build on it. | packages/agent/src/tasks-domain/task-workspace.service.ts, packages/agent/src/facades/workspace.facade.ts, docs/features/task-isolation.md, docs/features/tasks.md |
| Quality gates | Ships. Per-Task or Work checkDefaults; red required checks send the agent back up to maxGateAttempts (1–5). | docs/features/quality-gates.md |
| Merge policy | Ships. Five knobs resolved platform → tenant → org → Work → Agent; default allowAgentMerge: false; stable refusal codes. | docs/features/merge-policy.md, git.facade.ts (mergePullRequest) |
| Fleet | Ships. model-cli mode runs a local coding CLI in an isolated worktree, grades checks, pushes; multi-repo mounts (≤ 8); ask-human pause via .ever-works/QUESTION.md; browser-check job kind. Env grants are exact-name; prompt injection via a dependency README is a documented risk. | docs/features/fleet.md, docs/internal/feat-fleet-*-notes.md |
| Job runtimes | Partial. Trigger.dev is the registered runtime; other runtime plugins exist but the selector does not yet move the queue dispatchers (except the Fleet Agent-run path). | docs/features/job-runtimes.md, packages/tasks/src/trigger/trigger.module.ts |
| Missions | Ships. Typed Mission↔Work relations (created/improves/operates/markets/researches/retires); Missions are Idea → Work factories, not Task factories on an existing Work. | docs/features/missions.md |
| Goals | Ships. An iteration is a Task routed to a pinned/round-robin Agent; concurrency 1 by default. A Goal has no workId. | packages/agent/src/entities/goal.entity.ts, packages/agent/src/goals/goal-orchestrator.service.ts, docs/features/goals.md |
| Schedules | Ships. Task scheduled/recurring (RRULE/cron), Mission cron ticks, Goal check frequency. | docs/features/tasks.md, docs/scheduled-work-system.md |
| Agent & Skill templates | Ships — but read this before designing around it. The shipped agent templates are an in-code catalog (packages/agent/src/agents/agent-templates.ts:7,62, read by agent-templates.service.ts:56, written out as SOUL.md), and the ever-works/agents reader fetches manifest.json only (apps/api/src/agent-template-catalog.service.ts:50-51,191-212) — it does not read SOUL.md, .works/agent.yml or skills.yml (skills.yml has 0 references in any .ts; agent.yml exists only as one of five DB-inline file names, agent-file.service.ts:25). The Skills half is as described: SKILL.md from ever-works/skills (everworks-skills.plugin.ts:20, packages/agent-plugins/src/skills.ts:38). Loading agent templates from the catalog repo's files is new work (APW-04 plan:607 calls it "(new, additive)"). | apps/api/src/agents/agent-template-catalog.service.ts, packages/agent/src/agents/agent-templates.ts, docs/features/agents-catalog.md, docs/features/skills-catalog.md |
| Activity log | Ships. | docs/activity-log-spec.md, docs/features/activity.md, apps/api/src/activity-log |
| Run admission, Agent brake, safety rails (AW-23 / AW-24, added after authoring) | Ships (AW-24 P1 only). Every Agent run passes DEFAULT_RUN_ADMISSION_CHAIN: global stop flag (parks kill-switch) → Agent brake (parks agent-paused while the Agent is paused or archived) → Work valve → organization valve → credits. Every tool call passes SAFETY_GATE (platform stop, workspace pause, caps, trust ladder, …); commitToRepo, openPullRequest and facade:deploy are publish.external (default rung ask, shown but not enforced until an explicit rung is set or SHIPPED_DEFAULT_RUNG_POLICY becomes enforce in AW-24 P2). Approval proposals fold the rung in (stricter wins) via PROPOSAL_ACTION_CATEGORY. Task finalize pushes and pull requests are not gated by the ladder yet. | packages/agent/src/agents/run-admission-chain.ts, run-dispatch-gate.service.ts, agent-brake.service.ts, agent-halt.service.ts, packages/agent/src/safety/action-category.ts, safety-gate.port.ts, guardrail-interop.ts, packages/contracts/src/safety/action-category.types.ts, docs/specs/features/agent-workspace/AW-24-safety-rails/ |
6. Identity and cross-platform navigation
| Capability | State on develop | Evidence |
|---|---|---|
| Sign-in | Ships. Better Auth behind an abstraction; bearer() plugin; hashed random session tokens (older docs still say "JWT"); email/password, magic link, anonymous, GitHub/Google/Facebook/LinkedIn. Not an OpenID Connect provider (no JWKS, no authorization server). | apps/api/src/auth/providers/auth-provider.abstract.ts, apps/api/src/auth/providers/auth-runtime.instance.ts |
| Credential path on the request (AW-24, added after authoring) | Ships. AuthenticatedUser.authMethod?: 'session' | 'api-key', stamped by AuthSessionGuard on both branches (fleet-run ew_run_ tokens stamp 'api-key'). @HumanOnly() + HumanActorGuard refuse anything but 'session', fail closed on a missing stamp. APW-12 extends this union; it does not add the field. | apps/api/src/auth/types/auth.types.ts, apps/api/src/auth/guards/auth-session.guard.ts, apps/api/src/safety/guards/human-actor.guard.ts |
| Token hand-off to local clients | Ships — do not extend. /api/auth/authorize + addSessionTokenToUrl put the session token into a query string for allow-listed local hosts (CLI, node). Not a pattern for cross-site SSO. | apps/web/src/app/api/auth/authorize/route.ts, apps/web/src/lib/utils/url.ts |
| API keys | Ships. ew_live_ keys, ≤ 10 per user, full user powers, no scopes. | docs/features/api-keys.md |
| In-product switchers | Ships. Organization switcher (WorkspaceSwitcher), Work switcher (WorkSwitcher), command palette. No cross-platform launcher. | apps/web/src/components/layout/WorkspaceSwitcher.tsx, apps/web/src/components/dashboard/WorkSwitcher.tsx |
| Live URLs a launcher can list | Ships. WorkDeployment, WorkCustomDomain, deployProvider, observe URLs on the Work. | packages/agent/src/entities/work.entity.ts |
7. Launch-parity backlog items this program closes or touches
docs/internal/launch-parity-backlog.md: G-24 ungate managed hosting (APW-06/10), G-22 vertical
presets, gallery and remix = fork into your account (APW-01/03), G-09 enterprise identity — "no page may
claim SSO" until it ships (APW-12 must respect this in every doc and UI string until Ever ID is live).