Skip to content

feat(cloud): connected service with Clerk, Convex, dashboard, and connected CLI - #77

Draft
xloxn69 wants to merge 27 commits into
mainfrom
cloud/connected-mvp
Draft

xloxn69 wants to merge 27 commits into
mainfrom
cloud/connected-mvp

Conversation

@xloxn69

@xloxn69 xloxn69 commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Draft. Do not merge: depends on 10 inherited v5 commits (see "Merge gate").

Problem

AgileFlow has no shared service: people and agents cannot see the same epics, stories, notes and runs, and the dashboard cannot control access or local settings (docs/10-research/2026-10-12-clerk-mcp-agileflow-cloud-mvp).

Solution

  • apps/cloud: optional connected service.
    • Convex backend: data, access policy, work, collaboration, controls, import/export, Clerk webhooks, and HTTP actions for /mcp (22 tools), /cli, /local-control and /api.
    • Dashboard: React/shadcn, served as static files by Vercel, which proxies the service paths to Convex.
    • Reference implementation: Node/PostgreSQL with the same contract.
  • Clerk compatibility (AGILEFLOW_CAPABILITY_SOURCE=grants). Clerk cannot issue custom OAuth scopes and omits aud on public-client tokens (measured), so:
    • capabilities are granted per connection by its owner in the dashboard, and new connections are read-only;
    • each endpoint accepts only its own clients;
    • a token without aud is accepted only when that client binding holds;
    • a present aud must still match exactly.
  • agileflow cloud: login, status, connect, work, import/export, local companion.
  • packages/work: pure rules made runtime-neutral (no behavior change).
  • vercel.json: the dashboard build is pinned in the repository, and Git-triggered deployments are disabled.

Left uncommitted on purpose: the plugin, connected-mode skill edits and registry rebuilds, because they are intertwined with separate in-progress skill changes.

Verification

Clean build of 520713fd (the only change since is the UI-only cb6e03c4, which was rebuilt the same way: npm ci, dashboard typecheck and static build on Node 24, with source verified before install, after build and after deploy) in a fresh worktree on Node 24.21.0 / npm 11.19.0:

  • npm ci ok
  • cloud, Convex, Work and CLI cloud tests: 191/191
  • apps/cloud typecheck clean
  • vercel build --prod with vercel.json completes
  • npm ci also ok on Node 20 / npm 10
  • The full repository suite passed earlier (715 passed, 9 skipped).

Development deployment (Convex spotted-eel-239, Clerk dev instance):

Check Result
Real CLI token (device flow, client 3VXvbE1fmKkQFR0r) typ at+jwt, exact issuer, org_id present, no aud
GET /cli/v1/context 200: workspace, project as editor (never admin)
Read tools on the fixture project 200
agileflow_work_create / note_add without a grant 403 CAPABILITY_REQUIRED with a dashboard link
Same CLI token at /mcp and /local-control 403 CLIENT_NOT_ALLOWED
Refresh-token grant ok: refresh token rotated, same connection
/dev/session 404 (dev auth off)

Safari acceptance: pass on protected preview f8gg3pm8t, built from a source-verified clean checkout of cb6e03c4, bundle index-BPWlbcRC.js:

  • Vercel protection passed with the existing session.
  • Google sign-in works, the organization is shown correctly, and the CLI connection is listed as read-only.
  • In "Manage connections", the ordinary link Manage capabilities: 3VXvbE1fmKkQFR0r (cli) navigates on a native Safari click to the owner form: four enabled, unchecked capabilities, Save disabled (screenshot inspected).
  • No grants were changed.

Release under approval: cb6e03c4. It supersedes 520713fd only by the UI fix that moves management links outside the table (cb6e03c4). Auth behavior, destinations and permissions in the production batch are unchanged.

Remaining gates

  • Merge gate: the cloud commits build on 10 unmerged v5 commits (a797f2a9 … 5c421ba4). The first cloud commit conflicts on main in packages/work. Review and merge those separately first (suggested: their own PR), then this one.
  • Dev grant test (approval pending): the owner grants work:write to the CLI connection, one real-token create succeeds, the owner revokes, and the next create gets CAPABILITY_REQUIRED.
  • Production rollout (approval pending):
    • Clerk prod: same public PKCE clients, dynamic client registration, aud claim, webhook.
    • Convex prod calm-marten-391: environment with AGILEFLOW_CAPABILITY_SOURCE=grants, then deploy.
    • Vercel agileflow-dashboard:
      • settings: root directory = repository root, framework Other, Node 24.x, Ignored Build Step exit 0, Git stays connected
      • deploy the prebuilt output to production
      • add app.agileflow.projectquestorg.com, and redirect dashboard. to it
    • Deploy revision: cb6e03c495b4fb199d79025b2beb2284c4279ada, through the guarded clean build.
    • Rollback target: dpl_84NC649sii1Ht9stXvatz2rRFHim.
  • Google sign-in in production: needs the owner's Google Cloud OAuth client. Redirect URI: https://clerk.agileflow.projectquestorg.com/v1/oauth_callback.
  • Stage 0, still to run against Clerk:
    • MCP:
      1. Claude Code and Codex register through dynamic client registration.
      2. They complete consent and the organization choice, and their tokens are accepted at /mcp (client binding: dynamically registered).
      3. Reads are ok; a write gets CAPABILITY_REQUIRED until the owner grants; refresh works.
      4. A dynamically registered client deleted at Clerk is rejected within 10 minutes.
      5. Cursor is not available on the test machine.
    • Companion:
      1. Local-control sign-in with the companion client.
      2. Enrollment approved in the dashboard; read-only baseline (local:observe).
      3. The owner grants local:apply; then one approved setting is applied and receipted; revocation is checked.
      4. macOS has not been run.
    • Production: repeat the CLI read, refresh and rejection checks on app.agileflow.projectquestorg.com.

Dev grant/revoke probe receipts (2026-10-13)

  • Dev connection conn_5w0Io6PMaC_RmbB6 (CLI client, /cli), grants managed only through the owner's dashboard session (never via Convex directly).
  • With grants reduced to work:write only: STORY-CV032GQ8 created; notes/runs writes denied 403 CAPABILITY_REQUIRED.
  • After the owner revoked all grants (policyRevision 5): a real-token create was refused 403 CAPABILITY_REQUIRED; the fixture held exactly one story.
  • Owner restored the four-grant baseline (notes:write, work:write, controls:request, runs:write) in the dashboard; the save was confirmed.
  • Owner cancelled STORY-CV032GQ8 through the dashboard human session: now cancelled at v2, with an audit reason and history backlog -> cancelled. No other data was created.

Production rollout receipts (2026-10-13)

  • Convex calm-marten-391 runs cb6e03c4 in grants mode, without dev auth.
  • Vercel dpl_AqZ6DWU4PLWr7i6WMLMbDq9pKspv is built from the guarded clean cb6e03c4, with ignored build step exit 0.
  • app.agileflow.projectquestorg.com added (new CNAME); dashboard. now 308-redirects to app..
  • Live checks: / 200, /healthz 200, PRM resource https://app.agileflow.projectquestorg.com/mcp with issuer https://clerk.agileflow.projectquestorg.com and scopes user:org:read offline_access, anonymous /mcp 401, /dev/session 404.
  • Rollback: vercel rollback dpl_84NC649sii1Ht9stXvatz2rRFHim.

…coverage

- New opt-in @agileflow/engineering pack (not installed by default):
  writing-tests, refactoring-safely, writing-commits, reviewing-security,
  profiling-performance, planning-migrations
- Explicit boundaries: reviewing-changes finds defects in a diff,
  verifying-changes proves one behavior, reviewing-story checks acceptance
  criteria and the Definition of Done, writing-tests builds the suite
- reviewing-story and working-story 1.1.0 record per-criterion evidence
  with `agileflow work evidence`; checked boxes alone are never proof
- Every official skill has a happy path, a failure or blocked path
  (`path:`), and tagged near-neighbor negatives
…ry cache

- Signed registry metadata (TUF subset): pinned ed25519 trust root with
  rotation, signed snapshot binding the manifest, rollback and expiry
  checks; dormant until the key ceremony pins a root
- registry:check verifies history against the manifest at the previous
  release tag and against the integrities pinned in the CLI
- `@agileflow/*` counts as official only from a registry the repository
  did not choose
- Package cache keyed by registry, so one registry never supplies bytes
  read as another's
- Redirects may not leave the registry origin
- Version metadata publishes the eval scenario count
…move

- Validate, stage the whole batch, re-check each skill immediately before
  replacing it, keep backups until the lock agrees, then record
- Per-skill journal with progress; recovery rolls forward or restores and
  reports what was not applied, and keeps any copy it cannot restore
- One ownership check for planning and applying
- Read-only commands show interrupted skills instead of false states
- Serialized stale-lock takeover; Windows retries for renames and deletes
… support

- Versioned installed-file comparison (hashVersion, executables): a
  whole-file CRLF checkout is clean, partial CRLF is not; exec-bit drift is
  repaired, never treated as a user edit
- Lock records render inputs (renderer, questionOverlay); sync reproduces
  the lock and never ping-pongs between CLI versions; renderer changes are
  explicit re-render items in update
- Lockfile format 2 only when the new fields are used; managed entries must
  record a well-formed integrity
- check grades providers as enforced, advisory, or visible, with per-skill
  discovery and invocation detail
- Real symlink/junction/mirror fallback tests; CI on Linux, macOS, Windows
  with a cross-machine LF-to-CRLF smoke
- Installs and updates review source, description, activation,
  instructions, files, scripts, allowed tools, frontmatter (hooks),
  requirements, and new scan findings; update --dry-run shows it in full
- update refuses a published version or git commit whose content changed
- sync asks before writing third-party content this machine has not
  installed (a teammate's lock change, a fresh clone); exit 3 without --yes,
  and approval is recorded only for content verified on disk
- verify reports registry signature status and checks locked official
  packages against the signed manifest
- Scenarios end as passed, failed, inconclusive, or not-run; infrastructure
  errors and ungraded criteria never pass and fail the gate
- Evidence kept on inconclusive runs, incremental reports, signal-safe
  cleanup, preflight before paid runs, provenance of the loaded SKILL.md
- Setup scripts restricted and credential-free; providers get only their
  own credentials; reports record exact versions and hashes
- eval --compare: no skill vs released vs candidate under matched,
  interleaved conditions, with deltas, intervals, and verdicts
- eval --pack: whole-pack activation matrix and regression check for newly
  added skills; held-out scenarios and deterministic run checks
- Nightly comparison of changed skills against their last release
… v4 import

- `work next` lists stories that can start now with the reason for each
- `work evidence` records per-criterion evidence; `work show` reports
  verified, stale, or not verified
- Writes run under the project lock, are atomic, and are refused when the
  file changed since it was read; duplicate IDs are flagged
- v4 import previews mappings, keeps legacy_id and legacy_source, uses
  stable IDs, and holds back conflicting items unless --prefer is given
- work init asks before installing an agile pack from a registry the
  repository chose; gitignore and control-character hardening
…ed JSON

- `add --adopt` brings skills already in .agents/skills or provider folders
  under AgileFlow: preview first, managed only when identical to a
  published version, backups in the machine cache, never unlinks a provider
- `agileflow outdated`: locked, wanted, and latest versions per skill
- search and info show activation, requirements, packs, and eval evidence
- create scaffolds references, a blocked-path eval, and neighbor hints
- One versioned JSON result for mutating commands; migrate --json and
  --dry-run; JSON mode never prompts
- Commands load lazily from split bundle chunks
- Require Node.js 22 or newer (Node 20 reached end of life)
- Publish with npm trusted publishing (OIDC); NPM_TOKEN is only a fallback
- Smoke-test the packed tarball in a clean HOME and PATH before tagging and
  publishing, and the published package on Linux, macOS, and Windows
- Document the registry key ceremony and the release checks
Move WorkError and the dependency-cycle finder into modules without Node
built-ins, and draw ID randomness from Web Crypto, so the lifecycle,
readiness, criteria, and ID rules can also run inside the connected
service's V8 functions. Behavior and exports are unchanged.
…n APIs

Add apps/cloud, an optional private deployment behind the connected mode:
- Convex backend: schema, access core (membership freshness, project
  grants, connection policy, idempotency, versions, revisions, activity),
  work, collaboration, controls, admin, import/export, Clerk webhooks, and
  HTTP actions for /mcp (22 tools), /cli, /local-control, and /api.
- Clerk compatibility mode (AGILEFLOW_CAPABILITY_SOURCE=grants): owner-only
  per-connection capability grants, read-only new connections, endpoint and
  client binding, and client-bound audience for tokens without aud.
- React dashboard (shadcn, app-shell) built as static files; Vercel serves
  it and proxies service paths to Convex.
- Node/PostgreSQL reference implementation with the same contract, a dev
  OAuth issuer, and tests for parity and self-hosting.
- Deployment, Stage 0, acceptance, and Clerk adaptation documentation.
Add the opt-in cloud command: OAuth + PKCE login with OS credential
storage (no silent plaintext fallback), status with four separate states,
connect/disconnect with a token-free manifest and binding re-verification,
work list/show/create/move/note through the service with no local fallback,
import preview and export, and the local companion (enroll, run, disconnect)
applying approved settings with the native config and update primitives.
Supports services that grant capabilities per connection (Clerk).
Safari exposed the in-table dialog trigger only as a selectable cell and
the dialog never opened. The table now links to #/connections/<id>, a page
with an inline capabilities form (no dialog or overlay). The owner grants
and revokes; administrators can only revoke. A capability named by a
CAPABILITY_REQUIRED link is shown as a hint, never preselected.
Vercel builds the dashboard as static output with npm ci and
apps/cloud/scripts/vercel-build.mjs, independent of dashboard settings.
Git-triggered deployments are disabled for projects rooted at the
repository, so production changes only through an explicit deploy of a
committed revision.
npm 11 (Node 24, the Vercel project's runtime) rejected the lockfile for
missing react, react-dom, and scheduler entries under the dashboard
workspace. Regenerated in lockfile-only mode: adds those three entries and
drops a duplicate nested esbuild under apps/cloud. npm ci succeeds on
Node 20 (npm 10) and Node 24 (npm 11).
@vercel

vercel Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
agileflow-website Error Error Oct 14, 2026 4:56pm UTC

Request Review

Safari exposed the Manage capabilities link inside the connections table as
plain cell text, and a click selected text instead of navigating. The
table now shows only the capability status; a separate "Manage
connections" navigation lists one link per connection the viewer may
manage (owner: manage; administrator: revoke existing grants).
The harness read scope-mode rejections only. It now reads capabilitySource
from discovery and expects CAPABILITY_REQUIRED tool errors and 403
CLIENT_NOT_ALLOWED cross-endpoint refusals in grants mode, adds anonymous
/cli, /local-control and /dev/session checks, and documents the Clerk
adaptation and the 2026-10-13 receipts.
Token file and login deadline overrides, a print-URL mode, an absolute login
deadline, wrong-state callbacks refused without aborting the pending login,
nonzero exit on any failed check including the invalid_grant refresh check,
and a context check that requires the token's organization binding.
- Replace Clerk's SignIn, OrganizationList, OrganizationSwitcher and
  UserButton with our own components on Clerk hooks: email code,
  password, Google, account creation, organization choose/create, and a
  sidebar account menu.
- Finish Clerk's required choose-organization step on our own page and
  return CLI OAuth sign-ins to Clerk's redirect_url (Frontend API only).
- Adopt the @Efferd dashboard-1/dashboard-2 layout and primitives while
  keeping AgileFlow navigation, project switcher and breadcrumbs.
- Serve /sign-in and /sign-up (Clerk Paths) as the app and move them to
  #/signin; Clerk's own redirects use these paths.
- Take redirect_url off the address before Clerk loads (Clerk acted on
  it while signed out), keep it per tab for 15 minutes, and continue it
  once after sign-in or organization choice via buildUrlWithAuth.
- Give Clerk a hash-aware router so sign-out returns to #/signin
  without a stuck loading screen.
- Continue a Google sign-up that still needs details on our page.

This branch had an error being deployed

1 failed deployment
Preview – agileflow-website — 41a7cd13 Deployed Oct 14, 2026 by vercel[bot]
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.

1 participant