@midhunxavier/code-flow 0.0.0-stage → 0.1.0-preview.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +122 -2
- package/bin/codeflow.mjs +8 -0
- package/bin/launcher.mjs +127 -0
- package/dist/remote-host.json +1 -0
- package/licenses/inter.txt +92 -0
- package/licenses/preact.txt +21 -0
- package/licenses/signals-core.txt +21 -0
- package/licenses/signals.txt +21 -0
- package/licenses/typescript-notices.txt +193 -0
- package/licenses/typescript.txt +55 -0
- package/licenses/uqr.txt +22 -0
- package/licenses/xterm-fit.txt +19 -0
- package/licenses/xterm.txt +21 -0
- package/package.json +34 -4
- package/public/assets/browser-7XI52A6V.js +8 -0
- package/public/assets/changes-EYFPASEI.js +1 -0
- package/public/assets/chunk-7H3ZLTKA.js +2 -0
- package/public/assets/chunk-L7TUCIYF.js +1 -0
- package/public/assets/chunk-LLMQG23J.js +163 -0
- package/public/assets/main-KIRM2OEK.js +1 -0
- package/public/assets/settings-QJZVW22Y.js +9 -0
- package/public/assets/styles-615EBB20.css +32 -0
- package/public/assets/terminal-A2FI2NAX.js +62 -0
- package/public/assets.json +1 -0
- package/public/bundle-meta.json +1 -0
- package/public/docs/.nojekyll +0 -0
- package/public/docs/accessibility.html +19 -0
- package/public/docs/acp-agents.html +117 -0
- package/public/docs/agent-containers.html +79 -0
- package/public/docs/api.html +1130 -0
- package/public/docs/app.js +342 -0
- package/public/docs/application-improvements.html +275 -0
- package/public/docs/architecture-explorer.html +19 -0
- package/public/docs/architecture.html +149 -0
- package/public/docs/auto-team.html +142 -0
- package/public/docs/automations.html +109 -0
- package/public/docs/checkpoint-review.html +37 -0
- package/public/docs/code-hosts.html +35 -0
- package/public/docs/code-intelligence.html +35 -0
- package/public/docs/configuration.html +346 -0
- package/public/docs/context-inspection.html +23 -0
- package/public/docs/coordinated-changes.html +28 -0
- package/public/docs/deferred-runs.html +25 -0
- package/public/docs/dependency-discovery.html +19 -0
- package/public/docs/documentation.html +84 -0
- package/public/docs/dynamic-teams-evaluation.html +174 -0
- package/public/docs/dynamic-teams-implementation-plan.html +882 -0
- package/public/docs/dynamic-teams-implementation-review-1.html +141 -0
- package/public/docs/dynamic-teams-plan-review-0.html +204 -0
- package/public/docs/extensions.html +42 -0
- package/public/docs/external-sources.html +96 -0
- package/public/docs/filesystem-policy.html +26 -0
- package/public/docs/filtered-tasks.html +44 -0
- package/public/docs/font-license.txt +92 -0
- package/public/docs/getting-started.html +118 -0
- package/public/docs/github-review-threads.html +26 -0
- package/public/docs/github.html +157 -0
- package/public/docs/help.html +69 -0
- package/public/docs/index.html +77 -0
- package/public/docs/installation.html +74 -0
- package/public/docs/launch-profiles.html +48 -0
- package/public/docs/maintenance.html +60 -0
- package/public/docs/memory-claims.html +31 -0
- package/public/docs/memory-storage.html +58 -0
- package/public/docs/notifications.html +39 -0
- package/public/docs/patterns.html +195 -0
- package/public/docs/performance-results.html +210 -0
- package/public/docs/performance.html +166 -0
- package/public/docs/project-conventions.html +22 -0
- package/public/docs/project-first-navigation-plan.html +587 -0
- package/public/docs/project-teams-implementation-plan.html +772 -0
- package/public/docs/project-teams.html +99 -0
- package/public/docs/provider-compatibility.html +20 -0
- package/public/docs/releasing.html +61 -0
- package/public/docs/remote-workers.html +64 -0
- package/public/docs/review-inbox.html +26 -0
- package/public/docs/run-storage.html +23 -0
- package/public/docs/runs.html +141 -0
- package/public/docs/search.json +1 -0
- package/public/docs/security.html +133 -0
- package/public/docs/shared-projects.html +31 -0
- package/public/docs/ssh-projects.html +60 -0
- package/public/docs/style.css +768 -0
- package/public/docs/task-reruns.html +30 -0
- package/public/docs/team-collaboration.html +379 -0
- package/public/docs/verification.html +22 -0
- package/public/docs/vscode.html +53 -0
- package/public/docs/worker-permission-verification.html +122 -0
- package/public/index.html +17 -0
- package/scripts/check-node.mjs +7 -0
- package/scripts/codeflow.mjs +55 -0
- package/scripts/pty.py +273 -0
- package/src/acp-connections.js +110 -0
- package/src/adapters/acp-presets.js +37 -0
- package/src/adapters/acp-types.js +0 -0
- package/src/adapters/acp.js +328 -0
- package/src/adapters/agy-auth.js +67 -0
- package/src/adapters/agy-isolation.js +223 -0
- package/src/adapters/agy.js +297 -0
- package/src/adapters/claude.js +220 -0
- package/src/adapters/codex-app-server.js +518 -0
- package/src/adapters/codex.js +299 -0
- package/src/adapters/errors.js +57 -0
- package/src/adapters/index.js +91 -0
- package/src/adapters/managed-permissions.js +37 -0
- package/src/adapters/model-discovery.js +100 -0
- package/src/adapters/process.js +418 -0
- package/src/adapters/team-tools.js +102 -0
- package/src/adapters/types.js +0 -0
- package/src/agent-container.js +155 -0
- package/src/approvals.js +121 -0
- package/src/architecture.js +456 -0
- package/src/assets.js +44 -0
- package/src/automation.js +901 -0
- package/src/certificate-renewal.js +75 -0
- package/src/chat-handoff.js +55 -0
- package/src/checkpoint-review.js +72 -0
- package/src/checks.js +303 -0
- package/src/code-host-git.js +102 -0
- package/src/code-hosts-api.js +99 -0
- package/src/code-hosts.js +482 -0
- package/src/code-intelligence-worker.mjs +452 -0
- package/src/code-intelligence.js +141 -0
- package/src/collab/api.js +365 -0
- package/src/collab/checkpoints.js +198 -0
- package/src/collab/connections.js +139 -0
- package/src/collab/host-execution.js +347 -0
- package/src/collab/hub-client.js +210 -0
- package/src/collab/link-api.js +229 -0
- package/src/collab/link.js +595 -0
- package/src/collab/model.js +496 -0
- package/src/collab/runner.js +1014 -0
- package/src/collab/store.js +1452 -0
- package/src/collab/terminals.js +361 -0
- package/src/collaboration-reviews.js +116 -0
- package/src/config.js +48 -0
- package/src/context-budget.js +14 -0
- package/src/context-inspection.js +204 -0
- package/src/context.js +154 -0
- package/src/conventions.js +283 -0
- package/src/coordinated-api.js +247 -0
- package/src/deferred-launch.js +82 -0
- package/src/deferred-runs.js +515 -0
- package/src/dependency-health.js +35 -0
- package/src/diff.js +43 -0
- package/src/docs-help.js +316 -0
- package/src/doctor.js +232 -0
- package/src/engine.js +4366 -0
- package/src/env.js +44 -0
- package/src/experience.js +50 -0
- package/src/extensions.js +144 -0
- package/src/filesystem-access.js +107 -0
- package/src/filesystem-policy.js +238 -0
- package/src/filtered-task-limits.js +93 -0
- package/src/filtered-tasks-api.js +53 -0
- package/src/filtered-tasks.js +576 -0
- package/src/fs.js +57 -0
- package/src/git.js +626 -0
- package/src/github-review-threads.js +181 -0
- package/src/github.js +538 -0
- package/src/http.js +69 -0
- package/src/improve-settings.js +38 -0
- package/src/improve.js +187 -0
- package/src/integrations.js +373 -0
- package/src/integrity.js +259 -0
- package/src/journey-api.js +77 -0
- package/src/journey-replay.js +65 -0
- package/src/journey-store.js +97 -0
- package/src/journeys.js +60 -0
- package/src/json.js +81 -0
- package/src/launch-profiles.js +292 -0
- package/src/learnings.js +80 -0
- package/src/log.js +39 -0
- package/src/maintenance.js +335 -0
- package/src/memory-analysis.js +182 -0
- package/src/memory-claims.js +153 -0
- package/src/memory-sqlite.js +236 -0
- package/src/memory.js +552 -0
- package/src/merge-validation.js +58 -0
- package/src/model-catalog.js +238 -0
- package/src/model-research.js +91 -0
- package/src/notes.js +176 -0
- package/src/notifications.js +413 -0
- package/src/patterns/auto-team-model.js +212 -0
- package/src/patterns/auto-team.js +659 -0
- package/src/patterns/council.js +199 -0
- package/src/patterns/debate.js +188 -0
- package/src/patterns/findings.js +141 -0
- package/src/patterns/index.js +19 -0
- package/src/patterns/loop.js +158 -0
- package/src/patterns/pipeline.js +125 -0
- package/src/patterns/prompts.js +181 -0
- package/src/patterns/race.js +147 -0
- package/src/patterns/schemas.js +40 -0
- package/src/patterns/solo.js +49 -0
- package/src/patterns/supervisor.js +235 -0
- package/src/patterns/task-draft.js +29 -0
- package/src/patterns/tdd.js +231 -0
- package/src/patterns/team-strategies.js +67 -0
- package/src/performance.js +43 -0
- package/src/persistence-status.js +35 -0
- package/src/phone-sessions.js +96 -0
- package/src/preview-overlay.js +383 -0
- package/src/preview.js +219 -0
- package/src/privacy.js +23 -0
- package/src/project-report.js +22 -0
- package/src/project-team-model.js +178 -0
- package/src/project-team-policy.js +42 -0
- package/src/project-team-store.js +213 -0
- package/src/project-teams-api.js +36 -0
- package/src/project-teams.js +551 -0
- package/src/projects.js +286 -0
- package/src/provider-eligibility.js +9 -0
- package/src/readiness.js +98 -0
- package/src/remote-tls.js +66 -0
- package/src/remote-workers/bundles.js +198 -0
- package/src/remote-workers/client.js +332 -0
- package/src/remote-workers/durability.js +37 -0
- package/src/remote-workers/protocol.js +68 -0
- package/src/remote-workers/stdio.js +138 -0
- package/src/remote-workers/worker.js +304 -0
- package/src/remote.js +204 -0
- package/src/repo-config.js +201 -0
- package/src/repo-coordination.js +732 -0
- package/src/repo-tree.js +106 -0
- package/src/retention-policy.js +466 -0
- package/src/review-inbox.js +38 -0
- package/src/routing.js +49 -0
- package/src/run-analysis.js +111 -0
- package/src/run-cold-store.js +231 -0
- package/src/run-environment.js +15 -0
- package/src/run-history.js +91 -0
- package/src/run-log.js +160 -0
- package/src/run-permissions.js +110 -0
- package/src/run-projection.js +75 -0
- package/src/run-recovery.js +53 -0
- package/src/run-status.js +54 -0
- package/src/serve.js +138 -0
- package/src/server.js +2738 -0
- package/src/shared-access.js +103 -0
- package/src/shared-accounts.js +301 -0
- package/src/shared-api.js +239 -0
- package/src/shell.js +346 -0
- package/src/ship.js +344 -0
- package/src/slots.js +74 -0
- package/src/snapshot.js +388 -0
- package/src/source-context.js +17 -0
- package/src/sse-writer.js +70 -0
- package/src/ssh-projects/bootstrap.mjs +95 -0
- package/src/ssh-projects/config.js +45 -0
- package/src/ssh-projects/gateway.js +143 -0
- package/src/ssh-projects/manager.js +320 -0
- package/src/ssh-projects/team-autostart.mjs +93 -0
- package/src/ssh-projects/team-remove.mjs +69 -0
- package/src/ssh-projects/team-status.mjs +39 -0
- package/src/ssh-projects/transport.js +116 -0
- package/src/stats.js +139 -0
- package/src/store.js +544 -0
- package/src/stream.js +91 -0
- package/src/sweeps.js +241 -0
- package/src/tailscale.js +101 -0
- package/src/task-draft.js +23 -0
- package/src/team-evaluation.js +242 -0
- package/src/team-mailbox.js +160 -0
- package/src/team-memory.js +84 -0
- package/src/team-rerun-graph.js +15 -0
- package/src/team-reruns.js +130 -0
- package/src/team-scheduler.js +121 -0
- package/src/team-template-store.js +98 -0
- package/src/team-templates.js +117 -0
- package/src/team-tool-client.mjs +79 -0
- package/src/team-tools.js +176 -0
- package/src/teams.js +0 -0
- package/src/templates.js +62 -0
- package/src/transcript.js +134 -0
- package/src/verification-integrity.js +27 -0
- package/src/verification.js +183 -0
- package/src/watch.js +195 -0
- package/src/work-queue.js +47 -0
- package/src/workflow-control.js +83 -0
- package/src/workspace-api.js +207 -0
- package/src/workspace-changes.js +61 -0
- package/src/workspace.js +146 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Team collaboration — code-flow guides and reference"><title>Team collaboration · code-flow</title><link rel="icon" href="data:image/png;base64,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"><link rel="stylesheet" href="style.css"><script src="app.js" defer></script></head>
|
|
3
|
+
<body data-page="team-collaboration"><a class="skip-link" href="#content">Skip to content</a>
|
|
4
|
+
<header class="topbar"><a class="brand" href="index.html"><img src="data:image/png;base64,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" width="30" height="30" alt=""><strong>Code Flow</strong><span>Docs</span></a><button class="search-trigger" id="open-search">Search documentation <kbd>⌘ K</kbd></button><div class="top-actions"><a href="https://github.com/midhunxavier/code-flow">GitHub ↗</a><button id="theme" aria-label="Change color theme">Theme</button><button id="open-help" class="primary" hidden aria-expanded="false" aria-controls="help-panel">Ask code-flow</button><button id="menu" aria-label="Toggle documentation navigation" aria-expanded="false" aria-controls="sidebar">☰</button></div></header>
|
|
5
|
+
<div class="layout"><nav class="sidebar" id="sidebar" aria-label="Documentation"><section><h2>Get started</h2><a href="index.html" >Overview</a><a href="installation.html" >Install Code Flow preview</a><a href="getting-started.html" >Getting started</a><a href="patterns.html" >Team patterns</a><a href="acp-agents.html" >ACP coding agents</a><a href="help.html" >Ask code-flow</a></section><section><h2>Work with agents</h2><a href="runs.html" >Runs and workspace</a><a href="auto-team.html" >Auto team</a><a href="project-teams.html" >Project missions (preview)</a><a href="review-inbox.html" >Review inbox</a><a href="verification.html" >Verification and review</a><a href="github.html" >GitHub, review and shipping</a><a href="github-review-threads.html" >GitHub review threads</a><a href="task-reruns.html" >Selective task reruns</a><a href="deferred-runs.html" >Deferred runs</a></section><section><h2>Your workspace</h2><a href="configuration.html" >Configuration</a><a href="context-inspection.html" >Context and budgets</a><a href="project-conventions.html" >Versioned project conventions</a><a href="checkpoint-review.html" >Checkpoints and reversions</a><a href="launch-profiles.html" >Service launch profiles</a><a href="code-intelligence.html" >Code intelligence</a><a href="architecture-explorer.html" >Architecture explorer</a><a href="memory-storage.html" >Project memory</a><a href="memory-claims.html" >Semantic claim review</a><a href="coordinated-changes.html" >Coordinated changes</a></section><section><h2>Connect and collaborate</h2><a href="team-collaboration.html" aria-current="page">Team collaboration</a><a href="shared-projects.html" >Shared project accounts</a><a href="ssh-projects.html" >SSH projects</a><a href="remote-workers.html" >Remote agent workers</a><a href="code-hosts.html" >GitLab and Bitbucket code workflows</a><a href="external-sources.html" >Read-only external sources</a><a href="automations.html" >Automations and away mode</a><a href="notifications.html" >Outbound notifications</a></section><section><h2>Operate safely</h2><a href="security.html" >Security, subscriptions and caveats</a><a href="filesystem-policy.html" >Project filesystem policy</a><a href="agent-containers.html" >Agent containers</a><a href="filtered-tasks.html" >Filtered Docker tasks</a><a href="dependency-discovery.html" >Dependency discovery</a><a href="maintenance.html" >Backup and maintenance</a></section><section><h2>Build and extend</h2><a href="architecture.html" >Architecture and development</a><a href="api.html" >Local API and command-line client</a><a href="extensions.html" >Provider and workflow extensions</a><a href="provider-compatibility.html" >Provider compatibility</a><a href="accessibility.html" >Accessibility acceptance</a><a href="performance.html" >Performance</a><a href="run-storage.html" >Run storage</a><a href="documentation.html" >Documentation and GitHub Pages</a><a href="releasing.html" >Preparing a preview release</a><a href="vscode.html" >Code Flow for VS Code</a></section><section><h2>Engineering records</h2><a href="application-improvements.html" >Application improvement program</a><a href="project-first-navigation-plan.html" >Project navigation review and implementation plan</a><a href="dynamic-teams-evaluation.html" >Dynamic teams: implementation evidence and rollout decision</a><a href="dynamic-teams-implementation-plan.html" >Dynamic teams, workflows, messaging, and memory</a><a href="dynamic-teams-implementation-review-1.html" >Review 1: the dynamic teams implementation</a><a href="worker-permission-verification.html" >Live worker permission verification</a><a href="dynamic-teams-plan-review-0.html" >Review 0: Dynamic teams implementation plan</a><a href="project-teams-implementation-plan.html" >Standing project teams implementation plan</a><a href="performance-results.html" >Measured performance: 19 October 2026</a></section><a class="app-link" id="back-app" hidden href="/">← Back to app</a></nav>
|
|
6
|
+
<main id="content" tabindex="-1"><div class="breadcrumb">Documentation <span>/</span> Connect and collaborate</div><article><h1 id="team-collaboration">Team collaboration</h1>
|
|
7
|
+
<p>Connect each teammate’s computer as a runner for its local repositories and CLI logins. Use explicit host-execution or terminal grants only when teammates should work on the team server itself.</p>
|
|
8
|
+
<p>Project → More → <strong>Board</strong> contains tasks on the project’s owning computer. Project → More → <strong>People</strong> contains members, roles and repository keys; the owner also gets existing account and execution/terminal grant controls. Configured boards become project tabs. The optional <strong>Show Board in the app menu</strong> preference only controls an unused shortcut: it never hides configured collaboration or its settings. Command search includes Board and People, with Team as a search alias.</p>
|
|
9
|
+
<p>Linked servers remain available through the connection-scoped <strong>Board</strong> entry and its <strong>Team connection</strong> selector. A linked project is not attached to a local project by a matching ID, name or repository path. The URL’s <code>team</code> query pins requests, downloads and the stream to that connection. Opening a local project’s Board or People switches the document to <code>team=local</code>; previous requests and subscriptions cannot become actions against the new source. Missing projects show an unavailable state instead of another board. Shared users see Board and Results plus People from their authorized board projection, including projects with repository keys but no server clone.</p>
|
|
10
|
+
<h2 id="choose-where-work-runs">Choose where work runs</h2>
|
|
11
|
+
<p>Team collaboration lets the people who work on a project share one <strong>team board</strong> of tasks and hand work between their computers. One ordinary code-flow instance acts as the <strong>team server</strong>: teammates reach it over HTTPS through Tailscale or another network and sign in with the existing <a href="shared-projects.html">shared project accounts</a>. Each teammate's own code-flow installation can be linked to that server as a <strong>runner</strong> ("this computer"): it executes board tasks locally, in a Git worktree, with that person's own agent CLIs and logins; publishes bounded progress and a final <strong>hand-over checkpoint</strong> (a verified Git bundle plus structured context) to the board; and can hand the task over to a teammate, who continues from the checkpoint with any agent. Reviews attach to checkpoint commits.</p>
|
|
12
|
+
<p>The team server never commands another machine. In the linked-runner workflow every connection is made outbound, from a teammate's computer to the server; execution starts from that computer's own code-flow, by its owner; and nothing on the server can start, steer or stop a run elsewhere. The server holds the board, the checkpoints and who is doing what. The work happens where the agents and their logins already are.</p>
|
|
13
|
+
<p>Vocabulary in this document: <em>team</em> and <em>teammates</em> are people, not the agents' <a href="auto-team.html">Auto team</a>; a <em>board task</em> is an entry on the team board, not an Auto-team task; a <em>hand-over checkpoint</em> is a published Git bundle, not one of the <a href="checkpoint-review.html">commit checkpoints</a> under <strong>Project → Repository tools → History</strong>; a <em>runner</em> is a teammate's own code-flow, not an <a href="remote-workers.html">SSH worker</a>. In the code and the tests the feature is called <code>collab</code>.</p>
|
|
14
|
+
<p>Deliberately absent in this version: live pairing in the same terminal; moving a provider's live session between machines; automatic merging of combined results (fetching checkpoints into local branches and the existing merge and verification flows is the integration path); issue-tracker links; the server pushing anything to teammates' machines. Opt-in host tasks and individual interactive terminals for shared users are described below.</p>
|
|
15
|
+
<h2 id="set-up-the-team-server">Set up the team server</h2>
|
|
16
|
+
<p>Open <strong>Settings → Connections → Share access → People → Set up team server</strong> for the guided setup. Choose <strong>This computer</strong> or a saved SSH server under <strong>Server</strong>. Setup targets that server’s own board, independently of the team selected in your browser tab. For an SSH server, choose the HTTPS port and click <strong>Set up on this server</strong>. Disconnected saved servers offer <strong>Connect and set up on this server</strong>. Then complete the five steps:</p>
|
|
17
|
+
<ol>
|
|
18
|
+
<li>Choose an existing project or create one, and set your name on the board. A local clone on the server is optional.</li>
|
|
19
|
+
<li>Define the shared repository keys, labels, Git URLs and default branches.</li>
|
|
20
|
+
<li>Choose Tailscale or another HTTPS network, enable team access, and create or import a trusted certificate using the existing secure-access controls. For another network, you manage the hostname and reachability. The wizard installs a separate team server on remote machines; the managed SSH workspace keeps its network listeners disabled.</li>
|
|
21
|
+
<li>Create teammate accounts or grant existing accounts access to this project. Other project roles are preserved.</li>
|
|
22
|
+
<li>Review the saved configuration and copy connection instructions containing the HTTPS server origin. Passwords and phone pairing links are never included.</li>
|
|
23
|
+
</ol>
|
|
24
|
+
<p>Saved steps remain if you close and reopen setup. You can defer secure access or accounts; the review then identifies the unfinished steps instead of reporting the server as ready. Keep the host running and ask a teammate to confirm they can connect through your network’s access rules. The individual settings below remain available.</p>
|
|
25
|
+
<p>For SSH hosting, the wizard uses the saved SSH connection and the bundled Code Flow release; no manual checkout or npm install is needed. The existing SSH requirements (Node.js 20+ and Git on the login PATH) apply. Installation lives under <code>~/.codeflow/team-server</code> on the remote machine, separate from <code>~/.codeflow/ssh-host</code>. Projects, accounts, certificates and team data live in <code>team-server/state</code>; the private owner token and process identity live in <code>team-server/runtime.json</code>. Setup forwards only the project, account, repository and secure-access operations it needs, through the authenticated SSH channel. The browser never receives the remote owner token.</p>
|
|
26
|
+
<p>Reopening setup reuses a running server and its port, including after disconnecting and reconnecting SSH. Disconnecting SSH or closing the local app leaves the team server running. <strong>Stop team server</strong> in the wizard stops an idle server and keeps its data; starting setup again restarts it. A running older release must be stopped explicitly before setup installs the current release. For Linux servers with systemd, choose <strong>Enable automatic startup</strong> after setup. Code Flow installs <code>~/.config/systemd/user/codeflow-team-server.service</code> and verifies both service enablement and <a href="https://www.freedesktop.org/software/systemd/man/latest/loginctl.html">user lingering</a>, which starts the user service manager at boot without an SSH login. If server policy blocks enabling linger, setup shows the administrator command and does not claim startup is ready. <strong>Check startup status</strong> rechecks the actual server configuration; <strong>Disable automatic startup</strong> disables boot startup without stopping the current server or disabling other user services.</p>
|
|
27
|
+
<p>Automatic startup uses the installed release, saved HTTPS port and existing data. Its foreground supervisor restarts on failures under systemd, forwards shutdown to the server, and never prints the owner credential. Enabling startup does not interrupt or duplicate a server that is already running. <strong>Stop team server</strong> stops the current process but leaves startup enabled for the next reboot; disable startup as well to keep it off across reboots. Non-Linux servers and systems without a working systemd user manager report that automatic startup is unavailable; you can still start them from setup. DNS, firewall permissions and certificate trust still need to allow teammates to reach the chosen HTTPS port. Create an account for yourself too if you want to add this server as a team connection on your own computer.</p>
|
|
28
|
+
<p>The team server is a normal code-flow instance with nothing extra installed. Its owner is a maintainer of every project on the board and executes board tasks in-process, on that computer, like any other run.</p>
|
|
29
|
+
<p><strong>Network.</strong> Turn on <strong>Settings → Connections → Share access</strong>, choose <strong>Tailscale · access anywhere</strong> and choose <strong>Set up secure remote access</strong> to configure HTTPS, as described in <a href="automations.html#remote-access-with-tailscale">Remote access with Tailscale</a>. Teammates sign in and runners enrol through that network listener; both are accepted only over HTTPS or a direct loopback connection, so the HTTP read-only link is not enough, and the listener refuses connections from the server computer itself. Allow the remote port (normally 4318) for your teammates' devices in your tailnet's <a href="https://tailscale.com/docs/features/access-control/grants">access rules</a>, and issue the certificate for this computer's tailnet name with <a href="https://tailscale.com/docs/how-to/set-up-https-certificates">Tailscale HTTPS certificates</a>; the link teammates use carries that name once TLS is configured.</p>
|
|
30
|
+
<p>Alternatively, choose <strong>Other HTTPS network</strong> in the wizard and import a trusted certificate for your server hostname. Configure DNS and network access to the remote port yourself; Tailscale is optional.</p>
|
|
31
|
+
<p><strong>Accounts.</strong> Create an account for each teammate under <strong>Settings → Connections → Share access → People</strong> and assign a role per project. Each role includes everything the roles before it may do:</p>
|
|
32
|
+
<div class="table-scroll" tabindex="0"><table>
|
|
33
|
+
<thead>
|
|
34
|
+
<tr>
|
|
35
|
+
<th>Role</th>
|
|
36
|
+
<th>On the team board</th>
|
|
37
|
+
</tr>
|
|
38
|
+
</thead>
|
|
39
|
+
<tbody><tr>
|
|
40
|
+
<td><strong>viewer</strong></td>
|
|
41
|
+
<td>reads the board, tasks, checkpoint manifests and discussion, and their own inbox</td>
|
|
42
|
+
</tr>
|
|
43
|
+
<tr>
|
|
44
|
+
<td><strong>reviewer</strong></td>
|
|
45
|
+
<td>also comments and @mentions teammates, and records a review (approve or request changes) against a checkpoint</td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<td><strong>contributor</strong></td>
|
|
49
|
+
<td>also creates and edits tasks, takes an unowned task, adds decisions, requests a review from a named teammate, proposes <strong>Send to agent</strong> instructions, starts, stops and hands over attempts on their own tasks, accepts hand-overs offered to them, downloads checkpoint bundles and connects their computer as a runner</td>
|
|
50
|
+
</tr>
|
|
51
|
+
<tr>
|
|
52
|
+
<td><strong>maintainer</strong></td>
|
|
53
|
+
<td>also assigns any owner, deletes tasks and checkpoints, defines a project's repositories and cancels any hand-over</td>
|
|
54
|
+
</tr>
|
|
55
|
+
</tbody></table>
|
|
56
|
+
</div><p><strong>Repositories.</strong> Under <strong>Settings → Connections → Share access → People → Team server</strong>, give each project its <strong>repository keys</strong>: a short key (up to 64 lowercase letters, digits or dashes, starting with a letter), a label and, for information only, the remote URL and default branch. A board task names its repository by key, every teammate maps the key to their own clone, and no local path ever reaches the server. The same card sets the owner's display name as teammates see it (<code>@owner</code> in a comment reaches the owner), links to the accounts page and, once remote access with HTTPS is on, shows the server's <code>https://</code> address under <strong>Address</strong>, without any path: that is what teammates enter when they connect their computers. Never hand out the phone link from <strong>Settings → Connections → Share access</strong> instead; its path is a secret. With remote access on but no TLS, the card says so and points to secure access setup in Settings.</p>
|
|
57
|
+
<h2 id="let-teammates-run-tasks-on-the-host">Let teammates run tasks on the host</h2>
|
|
58
|
+
<p>The host owner can enable <strong>Settings → Connections → Share access → People → Run teammates’ tasks on this computer</strong> per project. First define repository keys and map them to canonical repository folders belonging to that project. Choose the installed CLI (Codex, Claude Code or Antigravity), Safe or Standard agent permissions, time and step budgets, and the individual contributors or maintainers allowed to execute. A project role alone never grants host execution. Check that the provider account or billing arrangement supports your intended team usage; Code Flow launches the installed CLI with its existing login and does not transfer credentials.</p>
|
|
59
|
+
<p>An authorized teammate signs into the shared dashboard, takes a task, and chooses <strong>Run on host computer</strong>. The host runs a single-agent workflow in a Git worktree with the owner-selected CLI, starting from the latest checkpoint when one exists. The browser may close after queuing. Progress, requester attribution and downloadable checkpoint bundles appear on the task. Teammates can download the bundle or use their linked Code Flow installation to fetch it into their own checkout. Files and test commands execute on the host, not the teammate’s computer. Agent approval requests remain with the host owner.</p>
|
|
60
|
+
<p>The <strong>Host queue</strong> shows pending and active tasks in projects the viewer can access. The owner sets 1–4 concurrent host tasks (default 1); a FIFO queue admits at most 50 pending/active requests, and repeated clicks return the existing request. Requesters may remove or stop their own jobs; the host owner may stop any job. Other project members can view progress but cannot cancel someone else’s job. Existing local-runner and owner runs are outside this queue’s concurrency limit.</p>
|
|
61
|
+
<p>Queued work and grants are stored privately in <code>CODEFLOW_HOME/host-execution/queue.json</code>. The queue retains up to 200 recent completed records alongside active requests. Restart recovery reconciles already-started attempts without replaying them; ambiguous starts become interrupted and may require recovery on the task. A queued request fails if its task content, owner, repository mapping or execution policy changes before launch. Account, project-role and execution-grant revocation are rechecked before dispatch and on the queue’s two-second activity pass; active affected runs are stopped. Changed policies require submitting a new request. Checkpoint publication finishes before capacity is released.</p>
|
|
62
|
+
<p>Host execution uses this computer’s own board and repository mappings, independently of saved remote team connections. It is unavailable while filesystem restrictions are active. The agent-task grant does not grant an interactive terminal, a raw shell-command endpoint, arbitrary paths, CLI arguments, or owner-level run controls. However, the agents and repository checks can execute commands with the host’s existing authority. Git worktrees and project grants are not operating-system isolation: grant this feature only to people and projects trusted with that execution authority.</p>
|
|
63
|
+
<p>The closed API surface is <code>GET /api/host-execution</code>, owner-only <code>PUT /api/host-execution/settings {revision, policy?, concurrency?}</code>, <code>POST /api/host-execution/tasks/:taskId {revision}</code> and <code>POST /api/host-execution/jobs/:jobId/cancel {}</code>. Browser mutations require same-origin JSON. Runner bearer credentials cannot reach these routes. Shared queue projections omit repository paths, execution configuration and other users’ grants.</p>
|
|
64
|
+
<h2 id="give-trusted-teammates-an-interactive-terminal">Give trusted teammates an interactive terminal</h2>
|
|
65
|
+
<p>Under <strong>Settings → Connections → Share access → People → Teammate terminals</strong>, enable a project and select individual contributors or maintainers. This is a separate, default-off grant from agent tasks. Define the project's repository keys and map them to canonical local folders first. Python 3 PTY support is required on the host; terminals use this computer’s own board and repository mappings and are unavailable while filesystem restrictions are active.</p>
|
|
66
|
+
<p>A permitted teammate opens <strong>Board → Your host terminals</strong>, selects a starting repository and chooses <strong>Open terminal</strong>. Typing, pasting, Ctrl-C, full-screen CLI programs and window resizing use a real pseudo-terminal. They can use their own browser on their own computer, but commands, files and installed CLIs run on the host computer. They can reconnect to the same session after refreshing the page. These terminals run independently of the agent-task queue and are not attached to task worktrees or checkpoints.</p>
|
|
67
|
+
<p><strong>This grants trusted access to the host's operating-system account.</strong> A project controls who may open a shell and its starting folder; it does not restrict what commands, files, network resources or credentials that shell can reach. Shell users can edit files, start processes and use installed CLI logins. Separate sessions and application-level ownership are not isolation between people who share an OS account. Use only for teammates trusted with that authority.</p>
|
|
68
|
+
<p>Each teammate may have two terminals, with eight total on the host. Only the creator can read or type into a session through Code Flow. The owner sees session metadata and can close any session from Settings. Closing the browser or signing out disconnects the view but leaves the shell available until closed or timed out. After 30 minutes without keyboard input the shell closes, including any foreground command; receiving output or resizing does not reset that timer. Permission, account revision, role, repository mapping and host availability changes reject further input and close affected sessions on the next one-second cleanup pass. Code Flow shutdown closes sessions, and restart never restores them. Closing a terminal does not undo changes or guarantee termination of detached processes.</p>
|
|
69
|
+
<p>Grants and up to 500 open/close records are saved privately in <code>CODEFLOW_HOME/terminal-access.json</code>; settings show the most recent activity. Command text and output are not written to that audit, although shell history and CLI programs can write their own files. A bounded in-memory output buffer supports reconnects. Terminal output is raw and can contain host paths and secrets; it is not a sanitized shared-review projection.</p>
|
|
70
|
+
<p>The dedicated API is <code>GET/POST /api/team-terminals</code>, owner-only <code>PUT /api/team-terminals/settings {revision, grant}</code>, <code>DELETE /api/team-terminals/:id {}</code>, <code>GET /api/team-terminals/:id/events</code>, and <code>POST /api/team-terminals/:id/input</code> or <code>/resize</code>. Mutations require same-origin JSON. Streams recheck the browser session and terminal access on every frame and once per second, without renewing an idle login. Runner bearer credentials cannot reach these routes, and generic owner shell APIs remain unavailable to shared users.</p>
|
|
71
|
+
<h2 id="connect-your-own-computer">Connect your own computer</h2>
|
|
72
|
+
<p>Open <strong>Settings → Connections → Share access → People → This computer</strong> in your own code-flow, enter the server's <code>https://</code> address (the <strong>Address</strong> its owner sees under <strong>Settings → Connections → Share access → People → Team server</strong>), your account's username and password, and a name for this machine (your hostname by default), and choose <strong>Connect this computer</strong>. Your code-flow sends the credentials once to the server's enrolment route, which verifies them exactly like sign-in (same rate limits, same HTTPS-or-loopback rule) without creating a browser session, requires a contributor role in at least one project, and answers with a per-machine <strong>runner credential</strong>, returned once and kept in the link. Plain <code>http://</code> is accepted only for loopback addresses. The credentials, and later the runner credential, go only to the address you entered: a server that redirects the request is refused with 502 "The team server at <code><url></code> redirected the request; code-flow talks only to the address you entered, so enter the address the server itself answers at", and a certificate this computer does not trust with 502 "This computer does not trust the team server's certificate at <code><url></code> (…)": give the server a Tailscale HTTPS certificate for its tailnet name, or trust its certificate on this computer with <code>NODE_EXTRA_CA_CERTS</code>. Up to 20 team servers can be saved at once. Your own board remains available even when it holds tasks. Adding the same server twice is refused; choose its saved connection instead. The team server and every linked computer must run the same code-flow version: the checkpoint protocol is not negotiated between versions, and an older team server refuses a newer computer's checkpoint manifests (400, unknown field <code>id</code>).</p>
|
|
73
|
+
<p>Use <strong>Add team connection</strong> in <strong>Settings → Connections → Share access → People → This computer</strong> for another team. The <strong>Team connection</strong> selector in Settings and on the board switches between saved servers and <strong>This computer’s own board</strong>. Each server supplies its own projects and account roles; map repositories after choosing that server. Projects and repository keys that happen to have the same IDs on two servers remain separate. Switching leaves all connections and ongoing runs active. Each browser tab keeps its selection in its URL (<code>?team=<connection id></code>), so bookmarked task links and tabs for different teams retain their destination.</p>
|
|
74
|
+
<p>Connections are stored under <code>CODEFLOW_HOME/team-connections/<connection id>.json</code> (mode 0600), with separate credentials, repository mappings and defaults. Passwords are exchanged once for a runner credential and never saved. The old single connection in <code>team-link.json</code> is automatically moved to <code>team-connections/legacy.json</code>; its runner identity and existing attempt journal are preserved. An unlinked <code>team-link.json</code> still holds the local board's mappings.</p>
|
|
75
|
+
<p>Under <strong>Settings → Connections → Share access → People → Repositories</strong>, map each repository key of each project to a clone on this computer (<strong>Use current repository</strong> fills in the repository you have open). A task whose key is unmapped asks you to map it before it can start. Each saved connection has its own event stream and runner, so progress, checkpoints and recovery always go to the team that owns the task, regardless of the visible team.</p>
|
|
76
|
+
<p><strong>Disconnect this team</strong> removes only the selected connection and revokes its runner credential (best effort). Stop or reconcile active/unknown attempts and settle pending checkpoints first. Its old mappings and local attempt records remain on disk for inspection; a new connection gets its own mappings and runner identity. Other teams and the local board keep working.</p>
|
|
77
|
+
<p>What never leaves this computer: your agent CLI logins, the files <code>copy</code> brings into worktrees (<code>.env</code> and the like), run transcripts and agent events, local paths and the run's private context. Of the run itself, the server receives only the progress fields and checkpoints described below. Uploaded text is filtered for recognized credentials, environment secrets and local absolute paths before it is truncated. This filtering does not inspect committed Git objects: only commit files intended to be shared with the project. Each teammate runs tasks with their own subscriptions and CLI logins on their own machine, which is the <a href="security.html#how-code-flow-uses-your-subscriptions">boundary each vendor draws</a>.</p>
|
|
78
|
+
<h2 id="the-team-board-and-tasks">The team board and tasks</h2>
|
|
79
|
+
<p><strong>Team</strong> in the sidebar (also the command palette entry <strong>Team board</strong>; <code>#/team</code>, or <code>#/team/project/<id></code> for one project) shows a column per status, <strong>Planned</strong>, <strong>Working</strong>, <strong>Blocked</strong>, <strong>In review</strong> and <strong>Done</strong>, filtered by project, by owner (<strong>Mine</strong>) and by status, next to your personal inbox. Shared users see the same board under the <strong>Team</strong> tab of their review dashboard. Contributors can run their own tasks on their linked computer, or queue them on the host when its owner has granted execution for the project.</p>
|
|
80
|
+
<p>A board task belongs to one project and one repository key and has a title (1–200 characters), a goal (up to 16 KiB) and acceptance criteria (8 KiB), an optional base branch or tag, an owner, up to 20 collaborators, a reviewer, up to 20 tasks it depends on, up to 10 labels and a <code>revision</code>. Every save carries the revision it was based on; a stale save fails with 409 "Task changed; reload before saving", and the page reloads the task while keeping your draft: the title editor and the blocker form stay open with your text, <strong>Goal</strong> and <strong>Acceptance</strong> keep <strong>Save</strong>, <strong>Discard</strong> and their <strong>Unsaved changes</strong> mark for as long as your text differs from the task (also once the reload shows a teammate's text), and a refused <strong>Depends on</strong> change snaps back to the task's list. A board holds at most 500 tasks, and a project at most 50 repository keys.</p>
|
|
81
|
+
<p>Status rules: any contributor may set any status, except that <strong>Done</strong> is refused (409) while an attempt is claimed, running or unknown or a hand-over is still offered, and <strong>Blocked</strong> requires a blocker text (up to 1000 characters) that is cleared on leaving Blocked. Claiming an attempt moves a Planned, Blocked or In review task to Working on its own, and is refused on a Done task (409 "Move the task out of Done before starting an attempt") until someone moves it back; finishing an attempt and accepting a hand-over leave the status alone, so the owner decides when the task goes to review or is done.</p>
|
|
82
|
+
<p>Ownership rules: a contributor takes a task nobody owns and gives back a task they own; a maintainer assigns or unassigns anyone; nobody changes the owner while an attempt is claimed, running or unknown on the task (409, naming the runner to stop first). The other way a task changes hands is an accepted hand-over. Either way, attempts the previous owner left paused or stopped become <strong>superseded</strong>: the next attempt starts from a checkpoint, never from one of those worktrees.</p>
|
|
83
|
+
<p>An <strong>attempt</strong> is one execution of a task on one runner, at most 50 per task. It records who ran it where, the exact base commit it started from, the checkpoint it continued from, its run id on that computer, its state (claimed, running, paused, finished, failed, stopped, unknown or superseded), its last progress report and the checkpoint it produced. Only one attempt can hold execution (claimed, running or unknown) on a task at a time, and nothing can be claimed while a hand-over is offered; the same rule refuses a report that would revive a paused, stopped or unknown attempt (409 "Stop the attempt running on <code><runner></code> before resuming this one", or "Accept, decline or cancel the offered hand-over before resuming the attempt"); a revive is refused on a Done task as well (409 "Move the task out of Done before resuming the attempt"), and for a machine whose user no longer owns the task (403 "The task now belongs to <code><name></code>; they continue it from its latest checkpoint, or a project maintainer reassigns it", or "The task has no owner now; take it to start a new attempt from its latest checkpoint"). Once an hour the server marks a claimed or running attempt it has not heard from for 24 hours <strong>unknown</strong>, with a reason.</p>
|
|
84
|
+
<h2 id="drafting-a-task-with-an-agent">Drafting a task with an agent</h2>
|
|
85
|
+
<p>On <strong>Team</strong>, choose <strong>Draft with agent</strong>, select a project and repository, describe the idea, and choose an installed agent and the local repository folder. Drafting runs remain owner-only in local history, including when the repository belongs to a shared project. <strong>Generate draft</strong> starts a local read-only run with Safe permissions, a five-minute budget and at most two agent calls. It uses the selected base branch (or the clone's HEAD), skips repository setup/check commands and copied files, and does not create a shared task or claim an execution attempt. The run remains available in run history; <strong>Open drafting run</strong> shows its details and <strong>Stop drafting</strong> cancels it.</p>
|
|
86
|
+
<p>Review the proposed title, goal (including scope, implementation plan and questions) and acceptance criteria, then choose <strong>Use draft in form</strong>. Edit those fields and the human owner/reviewer before <strong>Create task</strong>. Saving opens the task, ready for <strong>Build with agents</strong>; creating a task never starts a build automatically. The ordinary <strong>New task</strong> form remains available without an agent. Agent drafting and execution are local-computer controls, unavailable in the shared browser dashboard.</p>
|
|
87
|
+
<h2 id="running-a-task-on-your-computer">Running a task on your computer</h2>
|
|
88
|
+
<p>Open the task and choose <strong>Build with agents</strong>: you must own the task, and this computer must be linked or be the team server. Pick the repository folder (prefilled from your mapping), workflow, agents and permissions. Single agent suits small changes; Auto team supports a coordinator and multiple worker/reviewer providers. Models and reasoning can be adjusted in the dialog, along with the check command, time budget and agent call budget. Leave the check command blank to use the repository default (workflows requiring a check ask for an explicit command). Select your settings, and tick <strong>Continue from the latest checkpoint</strong> when one exists. Your code-flow then, in order:</p>
|
|
89
|
+
<ol>
|
|
90
|
+
<li>resolves the base commit: the latest checkpoint's commit when continuing (downloaded and imported first, as described under <a href="#handing-a-task-over">Handing a task over</a>), otherwise the task's base branch, or <code>HEAD</code> of your clone, and checks that the repository can carry checkpoints: one with a submodule, a checkout filter such as Git LFS in <code>.gitattributes</code>, or a tree over 20,000 files, 256 MiB or 100 attribute files is refused before anything is claimed (400 "This repository cannot carry team checkpoints (…); use a repository without submodules or checkout filters for board tasks");</li>
|
|
91
|
+
<li>writes a local attempt record, then <strong>claims</strong> the attempt on the server under a fresh attempt id: a repeated claim with the same id is idempotent, the server refuses while another attempt is claimed, running or unknown or a hand-over is offered, and a continuation must start from the latest checkpoint unless you are a maintainer; an earlier attempt of the task that is stuck on this very computer (claimed, with nothing running behind it) is settled first instead of blocking the start;</li>
|
|
92
|
+
<li>starts an ordinary run in a worktree of your clone, on the engine's usual <code>codeflow/<run id>/<worktree></code> branch (shown as the attempt's branch; only fetched checkpoints land on <code>team/<task id>/…</code> branches), with a prompt made of the task's title, goal, acceptance criteria and decisions and, when continuing, the checkpoint's context fenced as information; the prompt names the board task, and the run page shows a <strong>Team task</strong> link back to it;</li>
|
|
93
|
+
<li>publishes <strong>progress</strong> while the run goes: the current stage, a summary (4 KiB), the run status, up to 100 changed file paths, the last check (its command and whether it passed), the verdict, up to 10 blockers, the branch and head commit, and the step counts. Reports are numbered, so the server ignores one that arrives late and an attempt never moves backwards; publishing is throttled to one report every two seconds and stops when the run ends (the final snapshot, with the head and the changed files, travels with the finish), and a heartbeat every 20 seconds keeps the attempt live and brings back approved instructions;</li>
|
|
94
|
+
<li>when the run ends, creates a <strong>checkpoint</strong> if the branch moved past the base (its id is minted here, and the bundle is kept under <code>CODEFLOW_HOME/team-link/bundles/<checkpoint id>.bundle</code> until the server has it), uploads it, and finishes the attempt as <em>finished</em> (the run is done), <em>failed</em>, <em>stopped</em> (a budget or limit stop; resumable) or <em>paused</em> (cancelled, or interrupted by a restart: resume from this computer). When no checkpoint can be published for good (a repository with checkout filters or submodules, a bundle over 64 MiB, a manifest an older team server refuses), the attempt is still finished on the server, as <em>failed</em> when the run was done and otherwise in its paused or stopped state, with the reason "No checkpoint was published: <code><message></code>"; the task is released and the work stays on this computer's branch.</li>
|
|
95
|
+
</ol>
|
|
96
|
+
<p>Attempt ids are stable: a restart of your code-flow reconciles its local attempt records with the server instead of starting anything again. A run that is still going is re-attached and the reports the server missed are re-sent; a run that ended is published (an existing checkpoint and its kept bundle are reused); a run that is missing marks the attempt <strong>unknown</strong> with a reason and retains the reservation. Only a journal still at the pre-launch claiming step proves no run was started, allowing that claim to finish as failed automatically. Reconciliation never re-executes anything. A publication that failed is retried at once on reconnect, by a recovery pass that runs every minute with backoff (30 seconds, doubling to 30 minutes), or on demand with <code>POST /api/team-link/reconcile</code>; after 48 failed tries, about a day, the retries stop and this computer keeps the run's outcome in its local record. A refusal the server will never lift (401, the credential is gone; 403, this computer was re-linked under another runner id; 409, the attempt is already closed) ends the retries at once, and a bundle kept for a checkpoint that was given up is deleted.</p>
|
|
97
|
+
<p>A board card shows a live dot while the server has heard from the runner within the last 90 seconds. After that the task shows <strong>Connection lost; execution status unknown</strong>: the run may still be going on that computer, or may have ended without the server hearing about it. An expired heartbeat never releases execution ownership: starting another attempt, changing the owner and handing over remain blocked. The runner can reconnect and reconcile its state. If it cannot, the task owner or a project maintainer uses <strong>Recover attempt…</strong>, confirms the original agent has stopped (for example, by shutting down that computer), and records how they verified this. Recovery supersedes the old attempt and records the decision in History before releasing the task. A stale recovery is refused if the runner has already reconnected. <strong>Stop</strong> cancels the run (it stays resumable) and records the attempt as paused; <strong>Resume</strong> continues the same attempt under the same id, and is offered for a paused attempt, one stopped at a budget or limit and one marked unknown, when it ran on this computer. The server has the last word: Resume is refused with 409 once the task changed hands ("The task now belongs to <code><name></code>; they continue it from its latest checkpoint, or a project maintainer reassigns it"), on a Done task ("Move the task out of Done before resuming the attempt"), when the attempt was superseded or already ended, and while another attempt is claimed, running or unknown or a hand-over is offered; the server reserves execution before the local agent resumes, and an unreachable server leaves the agent stopped. If a running agent later loses its credential or its attempt is superseded, this computer stops it as well as its reports. <strong>Open run</strong> opens the run page for any attempt that ran on this computer, and the latest attempt stays on the task page after it ended ("No attempt yet." appears only on a task without attempts).</p>
|
|
98
|
+
<h2 id="discussion-review-requests-and-send-to-agent">Discussion, review requests and Send to agent</h2>
|
|
99
|
+
<p>Every task has a <strong>Discussion</strong> (comments of up to 4000 characters, 500 per task), <strong>Decisions</strong> (2000 characters each, 100 per task; they are snapshotted into every checkpoint and read by the next agent), <strong>Reviews</strong> and a collapsed <strong>History</strong> of up to 200 audit entries, oldest dropped. <code>@username</code> in a comment mentions a project member. Assignments, comments, mentions, review requests, recorded reviews, hand-over offers and answers, proposed instructions, blocked tasks and finished or failed attempts create entries in the personal <strong>inbox</strong> of the people concerned, 500 per person, oldest read items dropped first; reading is personal, so one teammate's read marks never clear another's, and you are never notified of your own actions. Removing project access stops new notifications and hides that project’s existing inbox items and unread counts. Only the hub owner can list or revoke other accounts’ runners; project maintainer permissions do not grant account-wide administration.</p>
|
|
100
|
+
<p>A contributor can request a review from a named teammate (403 "A project contributor role is required to request reviews" otherwise); a reviewer or higher records a review against the latest checkpoint. A comment can instead be sent as an instruction with the <strong>Send to agent</strong> toggle: it is <em>proposed</em>; the task owner, or a maintainer of the project, <em>approves</em> or <em>declines</em> it; an approved instruction is <em>delivered</em> on the runner's next heartbeat as a note to the attempt's run, the way your own messages to a running team are, exactly once, and marked so. The owner's own instructions are approved at once. The approval is the trust boundary: an approved instruction reaches the agent as a message to the run, attributed to its author ("Instruction from <code><name></code> via the team board"), whereas a checkpoint's context reaches the next agent fenced as information from teammates, the way <a href="github.html#untrusted-text">webhook and issue text</a> does, with a note that embedded instructions to change its task, tools or trust are not to be followed. Human comments otherwise never enter a prompt, as on the <a href="shared-projects.html">shared review</a> pages.</p>
|
|
101
|
+
<h2 id="handing-a-task-over">Handing a task over</h2>
|
|
102
|
+
<p>Choose <strong>Hand over…</strong> on a task you own, pick a teammate who is a contributor in the project, write a note (up to 4000 characters) and, if the worktree still has uncommitted tracked changes, tick <strong>Include uncommitted changes</strong> to commit them on the run branch as "Hand-over checkpoint"; without it the hand-over is refused with 409 "Commit, discard, or include uncommitted changes first". The sequence is:</p>
|
|
103
|
+
<ol>
|
|
104
|
+
<li>the current attempt must not be claimed, running or unknown: stop it or complete recovery first (409 otherwise);</li>
|
|
105
|
+
<li>your code-flow takes the attempt's latest checkpoint, or creates one from the worktree now; a retry after a failed offer reuses the pending checkpoint and uploads its kept bundle rather than creating another. When the task's current attempt is a teammate's (the task came back to you after a round trip), the task's latest checkpoint is offered, and the offer is refused with 409 when your old branch holds commits made after your attempt was superseded ("Branch <code><branch></code> on this computer holds work made after its attempt was superseded by a change of owner, which cannot be handed over; start a new attempt from the latest checkpoint to continue from it");</li>
|
|
106
|
+
<li>the server records an <strong>offer</strong> to the teammate and notifies them; the task stays yours, with its status;</li>
|
|
107
|
+
<li>the teammate chooses <strong>Accept and download</strong> on their computer: the bundle is downloaded and imported into their clone of the repository <em>before</em> ownership moves; a comment or review that lands during the download does not fail the acceptance, only an offer that no longer stands does (409 "This hand-over was already <code><state></code>");</li>
|
|
108
|
+
<li>the server then marks the hand-over accepted, makes them the owner and supersedes your paused or stopped attempts;</li>
|
|
109
|
+
<li>they continue with <strong>Build with agents</strong> and <strong>Continue from the latest checkpoint</strong>, with whatever pattern and agents they choose; the new attempt's base is the checkpoint commit, and the agent reads the checkpoint's context.</li>
|
|
110
|
+
</ol>
|
|
111
|
+
<p>A checkpoint is a cumulative Git bundle of all contributions since the original shared base commit, including earlier teammates’ work. Continuing an attempt starts at the prior checkpoint’s head, but the next bundle retains that checkpoint’s original base so a fresh teammate needs only the latest bundle, even after earlier bundles are deleted. The bundle is limited to 64 MiB and has a SHA-256 digest. Its manifest (up to 1.25 MiB) records: the checkpoint id, commit, base commit, branch, your note, the task's goal and acceptance criteria at that moment (16 KiB), the decisions, the last test result, the remaining work (8 KiB) and the changed files. Importing requires the base commit to exist in the recipient's repository; otherwise the import fails with 409 "Fetch <code><base></code> into this repository first" and the recipient fetches it from the repository's normal remote. Imports verify the file's size and digest, that the bundle's only ref names this checkpoint (otherwise 409 "The downloaded bundle does not belong to checkpoint <code><id></code>; it advertises <code>refs/codeflow/team/<other></code>. Delete this checkpoint and create a new one from the computer that holds the work", and the download is removed), the bundle's advertised head, Git's object checks, the ancestry from the base and the tree (no submodules, no checkout filters such as Git LFS), land only in <code>refs/codeflow/team/<checkpoint id></code>, and never touch <code>HEAD</code>, branches or the working tree. The checkpoint id is minted on the computer that creates the bundle and travels in the manifest, so the ref inside the bundle, the id on the board, the kept bundle file and the branch a fetch creates all carry the same id.</p>
|
|
112
|
+
<p>A failed download or import, a declined offer or a cancelled offer changes nothing on the server: the task stays with its current owner and keeps its checkpoints. The sender or a maintainer can <strong>Cancel hand-over</strong> while it is offered. Repositories with submodules or checkout filters cannot carry checkpoints and so cannot be used for board tasks; <strong>Build with agents</strong> refuses them before anything is claimed.</p>
|
|
113
|
+
<h2 id="reviews-and-integration">Reviews and integration</h2>
|
|
114
|
+
<p>A review (approve or request changes, with up to 4000 characters) is bound to a checkpoint and its commit. When a newer checkpoint appears, earlier reviews are marked <strong>stale</strong>, and the task's review state (approved, changes requested, pending, none) counts only the latest checkpoint's current reviews, the most recent verdict winning. Requesting a review notifies the reviewer and shows on the card.</p>
|
|
115
|
+
<p>To review or integrate on any computer, choose <strong>Fetch to this computer…</strong> on a checkpoint (contributor or higher, on a linked instance or the team server): the bundle is imported into <code>refs/codeflow/team/<id></code> and the local branch <code>team/<task id>/<first 8 characters of the checkpoint id></code> is pointed at it without being checked out; a branch that is checked out somewhere, or that holds commits the checkpoint lacks, is never moved. From there the existing flows apply: compare, validate and merge the branch as you would any result branch, or open a pull request from it. Merging the results of several tasks together is a manual step in this version; nothing merges on its own.</p>
|
|
116
|
+
<h2 id="storage-limits-and-boundaries">Storage, limits and boundaries</h2>
|
|
117
|
+
<p>On the team server everything lives under <code>CODEFLOW_HOME/team/</code> (mode 0700): <code>board.json</code> (each project's repository keys and its tasks with their attempts, checkpoint manifests, discussion, decisions, instructions, reviews, hand-overs and audit), <code>runners.json</code> (runner ids, names, last-seen times, the address each last connected from and the SHA-256 hashes of their credentials, never the credentials), <code>inbox.json</code> and <code>checkpoints/<checkpoint id>.bundle</code> (mode 0600). Files are written whole through a temporary file and renamed; a corrupt file is moved aside to <code><name>.corrupt-<time></code> and logged, and the board starts empty but writable; a file that cannot be read at all makes team storage unavailable, and every change fails with 503 until it is fixed. Every change is on disk before it is announced on the change streams, with one exception: heartbeats and progress reports on a running attempt (and a runner's last-seen time) are applied in memory and announced at once but reach <code>board.json</code> with the next durable change, the 30-second write-behind or shutdown; the first report of a claimed attempt, a resume, a finish and a checkpoint are written at once. At startup the team server removes what an interrupted upload left in <code>checkpoints/</code>: every <code><id>.bundle.<hex>.tmp</code>, and every <code><id>.bundle</code> that no checkpoint lists as available (not when <code>board.json</code> was set aside as corrupt, so a hand-repaired board keeps its bundles); the removal is logged. On a linked computer, <code>CODEFLOW_HOME/team-connections/<connection id>.json</code> holds each link. <code>CODEFLOW_HOME/team-runners/<connection id>/attempts/<attempt id>.json</code> ties local runs to attempts, and its sibling <code>bundles/</code> holds pending uploads. Local and migrated legacy records stay in <code>team-link/</code>, filtered by their hub origin.</p>
|
|
118
|
+
<p>Bounds: 500 tasks per board; per task 50 attempts, 50 checkpoints, 500 comments, 100 decisions, 50 instructions, 100 reviews, 50 hand-overs of history and 200 audit entries (oldest dropped); 50 repository keys per project; 20 collaborators, 20 dependencies and 10 labels of 40 characters per task; titles of 200 characters, goals of 16 KiB, acceptance criteria of 8 KiB, comments, notes, instructions and reviews of 4000 characters, decisions of 2000, blockers and reasons of 1000; progress summaries of 4 KiB, 100 changed-file paths of 300 characters and 10 blockers of 500 characters; checkpoint bundles of 64 MiB and 200 bundles on disk (when full, the oldest bundle of a Done task is deleted and its manifest kept; when none can be, the upload fails with 507 until checkpoints of finished tasks are deleted); 64 runners, 8 active per person; 500 inbox items per person and 5000 in all; request bodies of 64 KiB for task saves and repository keys, 192 KiB for progress reports, 1.25 MiB for checkpoint manifests (both sized so the character bounds fit in four-byte UTF-8), 64 MiB for bundles, 8 KiB for enrolment and 16 KiB otherwise; 16 MiB per board file, after which every change fails with 413 "The team board has reached its 16 MiB storage limit; delete finished tasks first" (deleting a checkpoint keeps its manifest, so only deleting tasks shrinks the board); change streams 4 per person and 128 in all, a stream being closed once 2 MiB of frames wait on its socket (the client reconnects with its cursor). An attempt counts as live for 90 seconds after its last heartbeat, is marked unknown after 24 hours without one, and a runner shows as online for 90 seconds after its last request.</p>
|
|
119
|
+
<p>Boundaries: a runner credential is a bearer token (<code>tr-</code> and 43 characters, shown once at enrolment) bound to one account and one machine. It reaches only <code>/api/team/*</code>: every other API route, the owner's and the shared review routes included, answers 403 "This credential only reaches the team API", the pages treat it as an anonymous visitor (it never becomes a session), and cookies sent beside it are ignored; it stops working as soon as the account is disabled or the runner is revoked (401 "This runner credential is not valid; connect this computer again in Settings → Connections → Share access → People"); and the server stores only its hash. The owner's own <code>CODEFLOW_TOKEN</code> is matched first, so an owner token that happens to have that shape still signs the owner in on the local listener. Runner enrolment is accepted over HTTPS or loopback only, like shared sign-in, and a linked computer refuses to store a plain <code>http://</code> server address that is not loopback. The network listener refuses the server computer's own connections, so the server's owner executes in-process rather than through a runner. Tasks are projected per role: a teammate sees only the projects where their account holds a role, people appear as an account id and display name, and no local path, run transcript, token or hash ever leaves the server. The other way round, a linked computer reads at most 64 KiB of an error answer from the server, and its progress, summaries, blockers, test commands, checkpoint text and failure reasons use the existing secret redaction before truncation and have its repository, worktree and home folders and any other absolute path replaced by <code><local path></code>. Every mutation carries a revision and fails with 409 when stale; a missing role answers 403 naming the role; a task you may not see is 404. Custom <a href="filesystem-policy.html">filesystem policies</a> pause starting attempts like other app-managed execution.</p>
|
|
120
|
+
<p>Encrypted <a href="maintenance.html">backups</a> include <code>team/</code> (the board, the runner registrations with their credential hashes, the inbox and the bundles) and the <code>team-link/</code> and <code>team-runners/</code> attempt journals, but leave out <code>team-connections/</code> and <code>team-link.json</code>, which carries this computer's runner credential, like the other credential stores; a restore of any archive skips it too and lists it under <code>omitted</code>. A restored computer therefore comes up not linked, without repository mappings or defaults: connect it again under <strong>Settings → Connections → Share access → People</strong> and map its repositories; its restored attempt records are read only to reconcile, never to start anything. The server side holds only credential hashes, and agent CLI logins are not in <code>CODEFLOW_HOME</code> at all. Revoke a runner on the team server (<strong>Settings → Connections → Share access → People → Runners</strong>) if a copy of a connection credential file leaves your control.</p>
|
|
121
|
+
<h2 id="api">API</h2>
|
|
122
|
+
<p>Paths are absolute; <code>/api/v1/team/*</code> and <code>/api/v1/team-link/*</code> are aliases. Browser sessions (the owner and shared accounts) and runner credentials (<code>Authorization: Bearer tr-…</code>) use the same team routes; the table says who may call. Runner mutations send <code>content-type: application/json</code> (the bundle upload <code>application/octet-stream</code>) and need no Origin header; browser mutations keep the same-origin JSON requirement of shared accounts. Mutations return the updated task; a stale <code>revision</code> fails with 409, a missing role with 403 naming the role, an unknown or invisible id with 404 "Task not found". Unknown team routes answer 404 "Unknown team operation" and never fall through to owner routes. Progress reports and heartbeats do not change the task revision.</p>
|
|
123
|
+
<div class="table-scroll" tabindex="0"><table>
|
|
124
|
+
<thead>
|
|
125
|
+
<tr>
|
|
126
|
+
<th>Operation</th>
|
|
127
|
+
<th>Request</th>
|
|
128
|
+
<th>Behavior</th>
|
|
129
|
+
</tr>
|
|
130
|
+
</thead>
|
|
131
|
+
<tbody><tr>
|
|
132
|
+
<td><code>POST /api/team/runners/connect</code></td>
|
|
133
|
+
<td><code>username</code>, <code>password</code>, <code>name</code></td>
|
|
134
|
+
<td>Anonymous enrolment over HTTPS or loopback: verifies the credentials like sign-in without creating a session, requires a contributor role in some project, and returns 201 with the runner, its credential (shown once), the user and the server's name.</td>
|
|
135
|
+
</tr>
|
|
136
|
+
<tr>
|
|
137
|
+
<td><code>GET /api/team/me</code></td>
|
|
138
|
+
<td>none</td>
|
|
139
|
+
<td>The caller's identity, project roles and own runners.</td>
|
|
140
|
+
</tr>
|
|
141
|
+
<tr>
|
|
142
|
+
<td><code>GET /api/team/board</code></td>
|
|
143
|
+
<td>optional <code>project</code> query</td>
|
|
144
|
+
<td>The board: the projects where the caller holds a role with their members and repository keys, task cards with the current attempt, latest checkpoint and hand-over, and the unread inbox count (viewer).</td>
|
|
145
|
+
</tr>
|
|
146
|
+
<tr>
|
|
147
|
+
<td><code>GET /api/team/tasks/:id</code></td>
|
|
148
|
+
<td>none</td>
|
|
149
|
+
<td>The full task (viewer in its project).</td>
|
|
150
|
+
</tr>
|
|
151
|
+
<tr>
|
|
152
|
+
<td><code>POST /api/team/tasks</code></td>
|
|
153
|
+
<td><code>projectId</code>, <code>repository</code>, <code>title</code>, <code>goal</code>, <code>acceptance</code>, optional <code>baseRef</code>, <code>owner</code>, <code>reviewer</code>, <code>collaborators</code>, <code>dependsOn</code>, <code>labels</code>, <code>status</code></td>
|
|
154
|
+
<td>Create a task (contributor); 201.</td>
|
|
155
|
+
</tr>
|
|
156
|
+
<tr>
|
|
157
|
+
<td><code>PUT /api/team/tasks/:id</code></td>
|
|
158
|
+
<td><code>revision</code> plus the changed fields</td>
|
|
159
|
+
<td>Partial save under the status and ownership rules; <code>null</code> clears an optional field.</td>
|
|
160
|
+
</tr>
|
|
161
|
+
<tr>
|
|
162
|
+
<td><code>DELETE /api/team/tasks/:id</code></td>
|
|
163
|
+
<td><code>revision</code></td>
|
|
164
|
+
<td>Delete a task (maintainer); <code>{deleted: true}</code>.</td>
|
|
165
|
+
</tr>
|
|
166
|
+
<tr>
|
|
167
|
+
<td><code>POST /api/team/tasks/:id/comments</code></td>
|
|
168
|
+
<td><code>text</code></td>
|
|
169
|
+
<td>Comment, with <code>@username</code> mentions (reviewer).</td>
|
|
170
|
+
</tr>
|
|
171
|
+
<tr>
|
|
172
|
+
<td><code>POST /api/team/tasks/:id/decisions</code></td>
|
|
173
|
+
<td><code>text</code></td>
|
|
174
|
+
<td>Record a decision (contributor).</td>
|
|
175
|
+
</tr>
|
|
176
|
+
<tr>
|
|
177
|
+
<td><code>POST /api/team/tasks/:id/review-request</code></td>
|
|
178
|
+
<td><code>reviewer</code>, <code>revision</code></td>
|
|
179
|
+
<td>Ask a teammate to review (contributor).</td>
|
|
180
|
+
</tr>
|
|
181
|
+
<tr>
|
|
182
|
+
<td><code>POST /api/team/tasks/:id/reviews</code></td>
|
|
183
|
+
<td><code>checkpointId</code>, <code>verdict=approve|request-changes</code>, <code>text</code>, <code>revision</code></td>
|
|
184
|
+
<td>Record a review against a checkpoint (reviewer).</td>
|
|
185
|
+
</tr>
|
|
186
|
+
<tr>
|
|
187
|
+
<td><code>POST /api/team/tasks/:id/instructions</code></td>
|
|
188
|
+
<td><code>text</code></td>
|
|
189
|
+
<td>Propose a <strong>Send to agent</strong> instruction (contributor); the task owner's own are approved at once.</td>
|
|
190
|
+
</tr>
|
|
191
|
+
<tr>
|
|
192
|
+
<td><code>POST /api/team/tasks/:id/instructions/:iid</code></td>
|
|
193
|
+
<td><code>action=approve|decline|delivered</code>, optional <code>attemptId</code></td>
|
|
194
|
+
<td>Approve or decline (the task owner or a maintainer); <code>delivered</code> is recorded by the attempt's runner.</td>
|
|
195
|
+
</tr>
|
|
196
|
+
<tr>
|
|
197
|
+
<td><code>POST /api/team/tasks/:id/attempts</code></td>
|
|
198
|
+
<td><code>attemptId</code>, <code>runnerId</code>, <code>runnerName</code>, <code>baseCommit</code>, optional <code>fromCheckpointId</code>, <code>revision</code></td>
|
|
199
|
+
<td>Claim an attempt (the task owner through their runner, or the server's owner in-process as runner <code>local</code>); idempotent on <code>attemptId</code>; 201. Refused (409) while another attempt is claimed, running or unknown, while a hand-over is offered, and on a Done task.</td>
|
|
200
|
+
</tr>
|
|
201
|
+
<tr>
|
|
202
|
+
<td><code>POST /api/team/attempts/:aid/progress</code></td>
|
|
203
|
+
<td><code>seq</code>, optional <code>runId</code>, the progress fields</td>
|
|
204
|
+
<td>Publish a numbered progress snapshot (the attempt's runner); a late number is ignored; 192 KiB. A report that would revive a paused, stopped or unknown attempt is refused (409) while another attempt of the task is claimed, running or unknown or a hand-over is offered, on a Done task (409 "Move the task out of Done before resuming the attempt"), and for a machine whose user no longer owns the task (403 "The task now belongs to <code><name></code>; they continue it from its latest checkpoint, or a project maintainer reassigns it").</td>
|
|
205
|
+
</tr>
|
|
206
|
+
<tr>
|
|
207
|
+
<td><code>POST /api/team/attempts/:aid/heartbeat</code></td>
|
|
208
|
+
<td>empty body</td>
|
|
209
|
+
<td>Keep the attempt live; returns the approved, undelivered instructions.</td>
|
|
210
|
+
</tr>
|
|
211
|
+
<tr>
|
|
212
|
+
<td><code>POST /api/team/attempts/:aid/finish</code></td>
|
|
213
|
+
<td><code>state</code>, optional <code>head</code>, <code>summary</code>, <code>reason</code></td>
|
|
214
|
+
<td>End the attempt as finished, failed, stopped, paused or unknown.</td>
|
|
215
|
+
</tr>
|
|
216
|
+
<tr>
|
|
217
|
+
<td><code>POST /api/team/attempts/:aid/recover</code></td>
|
|
218
|
+
<td><code>revision</code>, <code>reason</code>, <code>confirmedStopped=true</code></td>
|
|
219
|
+
<td>Recover an unknown attempt after confirming its original execution stopped (task owner or project maintainer). Supersedes it, records the decision and releases the task; stale revisions or a reconnected runner return 409.</td>
|
|
220
|
+
</tr>
|
|
221
|
+
<tr>
|
|
222
|
+
<td><code>POST /api/team/attempts/:aid/checkpoints</code></td>
|
|
223
|
+
<td>optional <code>id</code>, <code>commit</code>, <code>baseCommit</code>, <code>branch</code>, <code>size</code>, <code>sha256</code>, <code>note</code>, <code>requirements</code>, <code>decisions</code>, optional <code>testResults</code>, <code>remaining</code>, <code>changedFiles</code></td>
|
|
224
|
+
<td>Register a checkpoint manifest with <code>bundle: "pending"</code> (the attempt's runner); 201; 1.25 MiB. <code>id</code> (32 lowercase hexadecimal characters) becomes the checkpoint's id and ref <code>refs/codeflow/team/<id></code>; an id already on the board is refused (409), a malformed one 400, and without one the server generates the id.</td>
|
|
225
|
+
</tr>
|
|
226
|
+
<tr>
|
|
227
|
+
<td><code>PUT /api/team/checkpoints/:cid/bundle</code></td>
|
|
228
|
+
<td><code>application/octet-stream</code> body, <code>x-codeflow-sha256</code> header</td>
|
|
229
|
+
<td>Stream the bundle to disk (the checkpoint's runner); size and digest are verified before the checkpoint becomes available. A refusal (415, 400 on a size or digest mismatch, 409 when already uploaded or deleted, 507 when storage is full, 503 when the file could not be stored) is answered at once and the declared body is then drained, so a retry reads the answer; a body without a content-length (411) or declared over 64 MiB (413) is cut off once the answer is written.</td>
|
|
230
|
+
</tr>
|
|
231
|
+
<tr>
|
|
232
|
+
<td><code>GET /api/team/checkpoints/:cid</code></td>
|
|
233
|
+
<td>none</td>
|
|
234
|
+
<td>The checkpoint manifest (viewer).</td>
|
|
235
|
+
</tr>
|
|
236
|
+
<tr>
|
|
237
|
+
<td><code>GET /api/team/checkpoints/:cid/bundle</code></td>
|
|
238
|
+
<td>none</td>
|
|
239
|
+
<td>Download the bundle with <code>content-length</code> and <code>x-codeflow-sha256</code> (contributor).</td>
|
|
240
|
+
</tr>
|
|
241
|
+
<tr>
|
|
242
|
+
<td><code>DELETE /api/team/checkpoints/:cid</code></td>
|
|
243
|
+
<td>none</td>
|
|
244
|
+
<td>Delete a checkpoint and its bundle (maintainer); <code>{deleted: true}</code>.</td>
|
|
245
|
+
</tr>
|
|
246
|
+
<tr>
|
|
247
|
+
<td><code>POST /api/team/tasks/:id/handoff</code></td>
|
|
248
|
+
<td><code>to</code>, <code>checkpointId</code>, <code>note</code>, <code>revision</code></td>
|
|
249
|
+
<td>Offer a hand-over from an available checkpoint of the task (the task owner or a maintainer); refused while an attempt runs.</td>
|
|
250
|
+
</tr>
|
|
251
|
+
<tr>
|
|
252
|
+
<td><code>POST /api/team/tasks/:id/handoff/:hid</code></td>
|
|
253
|
+
<td><code>action=accept|decline|cancel</code>, <code>revision</code></td>
|
|
254
|
+
<td>Accept or decline (the recipient); cancel (the sender or a maintainer).</td>
|
|
255
|
+
</tr>
|
|
256
|
+
<tr>
|
|
257
|
+
<td><code>GET /api/team/inbox</code></td>
|
|
258
|
+
<td>optional <code>after</code> query</td>
|
|
259
|
+
<td>The caller's inbox items and unread count.</td>
|
|
260
|
+
</tr>
|
|
261
|
+
<tr>
|
|
262
|
+
<td><code>POST /api/team/inbox/read</code></td>
|
|
263
|
+
<td><code>ids</code>, or <code>all: true</code></td>
|
|
264
|
+
<td>Mark the caller's items read; returns <code>{unread}</code>.</td>
|
|
265
|
+
</tr>
|
|
266
|
+
<tr>
|
|
267
|
+
<td><code>GET /api/team/runners</code></td>
|
|
268
|
+
<td>none</td>
|
|
269
|
+
<td>The caller's runners; only the hub owner sees all.</td>
|
|
270
|
+
</tr>
|
|
271
|
+
<tr>
|
|
272
|
+
<td><code>DELETE /api/team/runners/:id</code></td>
|
|
273
|
+
<td>none</td>
|
|
274
|
+
<td>Revoke a runner (its user or the hub owner); <code>{revoked: true}</code>.</td>
|
|
275
|
+
</tr>
|
|
276
|
+
<tr>
|
|
277
|
+
<td><code>PUT /api/team/projects/:id/repositories</code></td>
|
|
278
|
+
<td><code>repositories</code>, <code>revision</code></td>
|
|
279
|
+
<td>Define the project's repository keys (maintainer).</td>
|
|
280
|
+
</tr>
|
|
281
|
+
<tr>
|
|
282
|
+
<td><code>PUT /api/team/profile</code></td>
|
|
283
|
+
<td><code>displayName</code></td>
|
|
284
|
+
<td>The owner's display name on the board (owner).</td>
|
|
285
|
+
</tr>
|
|
286
|
+
<tr>
|
|
287
|
+
<td><code>GET /api/team/events</code></td>
|
|
288
|
+
<td>optional <code>after=<epoch:seq></code> query</td>
|
|
289
|
+
<td>Server-sent events for the caller: <code>hello</code> with the epoch and sequence, then <code>change</code> events for the board and tasks in the caller's projects and <code>inbox</code> unread counts; a cursor the server no longer holds gets <code>resync</code>. Closed when the account changes or the runner is revoked, and when 2 MiB of frames wait on the socket.</td>
|
|
290
|
+
</tr>
|
|
291
|
+
</tbody></table>
|
|
292
|
+
</div><p>The owner-only routes below live on the local listener of each computer. On a linked computer they drive execution against the team server; on the team server itself they work in-process, and <code>linked</code> is false.</p>
|
|
293
|
+
<div class="table-scroll" tabindex="0"><table>
|
|
294
|
+
<thead>
|
|
295
|
+
<tr>
|
|
296
|
+
<th>Operation</th>
|
|
297
|
+
<th>Request</th>
|
|
298
|
+
<th>Behavior</th>
|
|
299
|
+
</tr>
|
|
300
|
+
</thead>
|
|
301
|
+
<tbody><tr>
|
|
302
|
+
<td><code>GET /api/team-link</code></td>
|
|
303
|
+
<td>none</td>
|
|
304
|
+
<td>The link: <code>linked</code>, the server address, user, server name, machine name, mappings and defaults, the connection state, the runner as the server reports it, the last sync and the last error.</td>
|
|
305
|
+
</tr>
|
|
306
|
+
<tr>
|
|
307
|
+
<td><code>POST /api/team-link/connect</code></td>
|
|
308
|
+
<td><code>url</code>, <code>username</code>, <code>password</code>, optional <code>name</code></td>
|
|
309
|
+
<td>Enrol this computer: <code>https://</code> only (plain <code>http://</code> for loopback), never following a redirect and only with a trusted certificate (502 otherwise), refused (409) while already connected or while the local board has tasks; saves the link and starts the change stream and reconciliation; 201.</td>
|
|
310
|
+
</tr>
|
|
311
|
+
<tr>
|
|
312
|
+
<td><code>DELETE /api/team-link</code></td>
|
|
313
|
+
<td>none</td>
|
|
314
|
+
<td>Revoke the runner on the server (best effort) and forget it here; mappings, defaults and local attempt records stay.</td>
|
|
315
|
+
</tr>
|
|
316
|
+
<tr>
|
|
317
|
+
<td><code>PUT /api/team-link/mappings</code></td>
|
|
318
|
+
<td><code>projectId</code>, <code>repository</code>, <code>path</code></td>
|
|
319
|
+
<td>Map a repository key to an absolute folder that is a Git repository.</td>
|
|
320
|
+
</tr>
|
|
321
|
+
<tr>
|
|
322
|
+
<td><code>POST /api/team-link/draft</code></td>
|
|
323
|
+
<td><code>projectId</code>, <code>repository</code>, <code>idea</code>, <code>agent</code>, optional <code>repo</code>, <code>baseRef</code>, <code>agentSettings</code></td>
|
|
324
|
+
<td>Start a bounded read-only task-drafting run on this computer; returns <code>{runId}</code>; 201. Requires contributor access to the project and an installed agent. Poll the ordinary run endpoint for the validated draft JSON in its completed summary.</td>
|
|
325
|
+
</tr>
|
|
326
|
+
<tr>
|
|
327
|
+
<td><code>POST /api/team-link/tasks/:id/start</code></td>
|
|
328
|
+
<td>optional <code>repo</code>, <code>pattern</code>, <code>roles</code>, optional <code>agentSettings</code>, <code>roleSettings</code>, <code>trust</code>, <code>loop</code> (<code>check</code>, <code>setup</code>, <code>maxMinutes</code>, <code>maxSteps</code>), <code>fromCheckpointId</code></td>
|
|
329
|
+
<td>Claim an attempt and start the run here; returns <code>{attemptId, runId}</code>; 201. Refused (400) before anything is claimed when the repository cannot carry checkpoints (a submodule, a checkout filter such as Git LFS, or a tree over 20,000 files, 256 MiB or 100 attribute files).</td>
|
|
330
|
+
</tr>
|
|
331
|
+
<tr>
|
|
332
|
+
<td><code>POST /api/team-link/tasks/:id/stop</code></td>
|
|
333
|
+
<td>empty body</td>
|
|
334
|
+
<td>Cancel the current attempt's run (resumable) and record it as paused.</td>
|
|
335
|
+
</tr>
|
|
336
|
+
<tr>
|
|
337
|
+
<td><code>POST /api/team-link/tasks/:id/resume</code></td>
|
|
338
|
+
<td>empty body</td>
|
|
339
|
+
<td>Resume this computer's paused, stopped or unknown attempt of the task under the same attempt id; refused (409) when the attempt was superseded or has ended, the task changed hands or is Done, another attempt is busy or a hand-over is offered.</td>
|
|
340
|
+
</tr>
|
|
341
|
+
<tr>
|
|
342
|
+
<td><code>POST /api/team-link/tasks/:id/handover</code></td>
|
|
343
|
+
<td><code>to</code>, <code>note</code>, optional <code>includeUncommitted</code></td>
|
|
344
|
+
<td>Create or reuse the checkpoint (a retry uploads the kept bundle), then offer the hand-over.</td>
|
|
345
|
+
</tr>
|
|
346
|
+
<tr>
|
|
347
|
+
<td><code>POST /api/team-link/tasks/:id/accept</code></td>
|
|
348
|
+
<td><code>handoffId</code>, optional <code>repo</code></td>
|
|
349
|
+
<td>Download and import the checkpoint, then accept the offer.</td>
|
|
350
|
+
</tr>
|
|
351
|
+
<tr>
|
|
352
|
+
<td><code>POST /api/team-link/checkpoints/:id/fetch</code></td>
|
|
353
|
+
<td><code>repo</code></td>
|
|
354
|
+
<td>Import a checkpoint and point <code>team/<task id>/<first 8 characters of the checkpoint id></code> at it; returns <code>{commit, branch, taskId, created}</code>.</td>
|
|
355
|
+
</tr>
|
|
356
|
+
<tr>
|
|
357
|
+
<td><code>GET /api/team-link/attempts</code></td>
|
|
358
|
+
<td>none</td>
|
|
359
|
+
<td>This computer's attempt records: which run belongs to which attempt, and what has been published.</td>
|
|
360
|
+
</tr>
|
|
361
|
+
<tr>
|
|
362
|
+
<td><code>POST /api/team-link/reconcile</code></td>
|
|
363
|
+
<td>empty body</td>
|
|
364
|
+
<td>Run the recovery pass now: settle claims whose answer was lost and retry unacknowledged finishes; returns <code>{attached, finished, removed, unknown, retried}</code>.</td>
|
|
365
|
+
</tr>
|
|
366
|
+
</tbody></table>
|
|
367
|
+
</div><p>In the owner's app the browser's own event stream carries the same board changes as a <code>team</code> topic, and the Team page also polls every 15 seconds; the shared dashboard's Board tab holds one <code>/api/team/events</code> stream instead (its runs stream is closed while the tab is shown), reloads on its frames and when the tab is shown again, and sends no periodic request of its own. Nothing in this API replays automatically: a restart reconciles local attempt records with the server and never starts a run again, and a dropped response is not proof that a mutation did not happen; reload the task before repeating one.</p>
|
|
368
|
+
<h2 id="validation-status">Validation status</h2>
|
|
369
|
+
<p><code>npx tsx --test test/collab-model.test.ts</code> covers the validators and bounds, status transitions, ownership rules, mentions, board summaries and the review state. <code>test/collab-store.test.ts</code> covers persistence and atomic writes, a corrupt file moved aside, revision conflicts, role enforcement inside the store, claim idempotency and the one-busy-attempt rule, progress ordering and liveness, finish states, checkpoint manifests with bundle storage and digest verification, the hand-over state machine, personal inbox read state, hashed and revoked runner credentials and the bounds. <code>test/collab-api.test.ts</code> drives the team API with fake requests: the closed route table, role refusals, a runner that cannot report on another person's attempt, projection privacy, the change stream, the enrolment handshake (bad passwords, viewer-only accounts and insecure transports refused), a refused upload answered over a real socket, and body limits that fit the character bounds in UTF-8. <code>test/collab-checkpoints.test.ts</code> creates a bundle from a repository with a base and two commits and imports it into a clone that has the base (ref created, <code>HEAD</code> untouched), a clone without it (clear error), with tampered bytes and over the size limit, and checks that the checkpoint context fences every teammate text. <code>test/collab-runner.test.ts</code> covers the runner against both hubs: progress and checkpoints, stop and resume with delivered instructions, hand-over and acceptance, reconciliation and the recovery pass, local paths scrubbed from reasons, refused finishes and resumes, a kept bundle retried, repositories that cannot carry checkpoints, the redirect and certificate refusals, bounded error bodies and the quiet-board stream. <code>test/collab-link.test.ts</code> is the acceptance test: it spawns a team server and two linked instances with their own homes and ports over loopback HTTP, with the fake agent CLIs, and walks a task from creation through an attempt, a checkpoint, a hand-over to the second teammate, a continuation from the checkpoint, a restart that starts nothing again and a revoked runner, and checks that a viewer session reads the board but cannot create tasks. <code>test/e2e/team.e2e.ts</code> opens the board in headless Chrome, defines a repository key under Settings → Connections → Share access → People and maps it, creates a task from the board form, opens it, adds a comment, a decision and a blocker, audits the board, the task page and Settings → Connections → Share access → People with axe in light, dark and phone layouts, and signs a shared contributor in who finds the task under the Board tab and comments without seeing any execution control.</p>
|
|
370
|
+
<p>No real Tailscale network, second physical machine, TLS certificate or real provider login was exercised by these tests; the acceptance test uses loopback HTTP, which enrolment accepts in place of HTTPS. Validate the Tailscale and HTTPS setup on your own tailnet before relying on it.</p>
|
|
371
|
+
<h3 id="selecting-connections-through-the-owner-api">Selecting connections through the owner API</h3>
|
|
372
|
+
<p><code>GET /api/team-link/connections</code> lists saved connection IDs and public connection state, including <code>local</code>. <code>POST /api/team-link/connect</code> adds a server and returns its ID. Scope <code>/api/team/*</code> and <code>/api/team-link/*</code> calls with <code>?teamConnection=<id></code> or the <code>X-Codeflow-Team</code> header; this selector is consumed locally and is never sent to another server. Downloads use the query form. <code>DELETE /api/team-link?teamConnection=<id></code> removes that connection. An unknown explicit ID returns 404; an omitted selector with multiple remote connections returns 409 rather than choosing a team. With one remote connection, unscoped clients continue to use it; with none, they use the local board. Shared accounts and runner credentials always access the receiving server's own board and cannot select the owner's other connections. The owner event stream uses <code>team:<connection id></code> topics.</p>
|
|
373
|
+
<hr>
|
|
374
|
+
<p><a href="index.html">Documentation library</a> · <a href="getting-started.html">Getting started</a> · <a href="help.html">Ask code-flow</a></p>
|
|
375
|
+
</article><footer><a href="https://github.com/midhunxavier/code-flow/blob/main/docs/team-collaboration.md">Edit this page on GitHub ↗</a><span>code-flow · 0.1.0-preview.1 · <a href="font-license.txt">Font license</a></span></footer><nav class="pagination" aria-label="Adjacent guides"><a href="coordinated-changes.html"><small>← Previous</small>Coordinated changes</a><a href="shared-projects.html"><small>Next →</small>Shared project accounts</a></nav></main>
|
|
376
|
+
<aside class="on-page" aria-label="On this page"><strong>On this page</strong><a class="depth-2" href="#choose-where-work-runs">Choose where work runs</a><a class="depth-2" href="#set-up-the-team-server">Set up the team server</a><a class="depth-2" href="#let-teammates-run-tasks-on-the-host">Let teammates run tasks on the host</a><a class="depth-2" href="#give-trusted-teammates-an-interactive-terminal">Give trusted teammates an interactive terminal</a><a class="depth-2" href="#connect-your-own-computer">Connect your own computer</a><a class="depth-2" href="#the-team-board-and-tasks">The team board and tasks</a><a class="depth-2" href="#drafting-a-task-with-an-agent">Drafting a task with an agent</a><a class="depth-2" href="#running-a-task-on-your-computer">Running a task on your computer</a><a class="depth-2" href="#discussion-review-requests-and-send-to-agent">Discussion, review requests and Send to agent</a><a class="depth-2" href="#handing-a-task-over">Handing a task over</a><a class="depth-2" href="#reviews-and-integration">Reviews and integration</a><a class="depth-2" href="#storage-limits-and-boundaries">Storage, limits and boundaries</a><a class="depth-2" href="#api">API</a><a class="depth-2" href="#validation-status">Validation status</a><a class="depth-3" href="#selecting-connections-through-the-owner-api">Selecting connections through the owner API</a></aside>
|
|
377
|
+
<aside id="help-panel" hidden aria-labelledby="help-title"><div class="chat-heading"><div><span class="eyebrow">Your AI companion</span><h2 id="help-title">Ask code-flow</h2></div><button id="close-help" aria-label="Close AI companion">✕</button></div><div class="chat-toolbar"><span>Grounded in your docs</span><button id="new-chat">New chat</button></div><div id="help-messages" role="log" aria-label="Help conversation" aria-live="polite"><div id="chat-welcome"><span class="chat-mark" aria-hidden="true">✦</span><h3>What would you like to do?</h3><p>Let’s find your next step. Ask about setup, workflows or something that’s unclear.</p><div class="suggestions"><button type="button" data-question="How do I start my first run?">Start my first run ↗</button><button type="button" data-question="What should I do when a check fails?">Understand a failed check ↗</button></div></div></div><p id="help-status" role="status">Checking your installed CLIs…</p><button id="retry-help" hidden>Retry connection</button><form id="help-form" hidden><label class="sr-only" for="question">Your question</label><textarea id="question" rows="3" maxlength="4000" placeholder="Ask a question…" required></textarea><div class="composer-controls"><label class="sr-only" for="help-agent">Use your CLI</label><select id="help-agent"></select><button type="button" id="stop-help" hidden>Stop</button><button class="primary" id="send-help" aria-label="Send message">Send ↗</button></div><small>Uses your CLI login and quota. Shift + Enter for a new line.</small></form><a id="help-guide" href="help.html">About your local companion →</a></aside></div>
|
|
378
|
+
<dialog id="search-dialog" aria-labelledby="search-title"><div class="dialog-title"><h2 id="search-title">Search documentation</h2><button data-close="search-dialog" aria-label="Close search">✕</button></div><label class="sr-only" for="search">Search all guides</label><input id="search" type="search" placeholder="Search workflows, settings, troubleshooting…" autocomplete="off"><div id="search-results" aria-live="polite"></div></dialog>
|
|
379
|
+
</body></html>
|