Code FlowDocs
GitHub ↗

Team collaboration

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.

Project → More → Board contains tasks on the project’s owning computer. The member count beside the project title opens People and access, with membership and computer status. The owner can expand Advanced administration for accounts and execution/terminal grants. Configured boards become project tabs. The optional Show Board in the app menu 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.

Linked servers remain available through the connection-scoped Board entry and its Team connection selector. A linked project is not attached to a local project by a matching ID, name or repository path. The URL’s team query pins requests, downloads and the stream to that connection. Opening a local project’s Board or People switches the document to team=local; 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.

Start with what you want to connect

Open Settings → Connections → Share access and choose:

Your goal Choose Next step
Continue your work on a phone or tablet Connect my devices Choose Wi-Fi or Tailscale, configure HTTPS for full control, then scan your private device QR code.
Join someone else’s project Join a team Open their invitation, choose your own account, then connect your own CodeFlow when you want to run tasks.
Give people access to a project Host a team Choose this computer or an SSH server, configure repositories and secure access, then invite teammates.

Manage existing connections and access retains the account, role, device, runner and execution-grant settings. Old Settings → Team and Remote access bookmarks still open the appropriate settings.

Invite and join a project

The server owner opens Project → Share, or the Teammates step in team-server setup. Choose a project and role, then Create invitation. Copy the link or let the recipient scan its QR code. Each link admits one person, expires after 24 hours, and can be revoked from Pending invitations. Only the token hash is saved; copy the link before leaving the page. Share it privately with its intended recipient.

Invitation creation in the app becomes available after secure network access is configured. The link uses the HTTPS server origin, without the owner's phone-pairing capability. The recipient must be able to reach that origin over the same Wi-Fi or permitted Tailscale network.

The recipient opens the invitation, checks the project and role, then creates their own account with a password of at least 15 characters or signs in with an existing shared account. Acceptance creates the account/membership and browser session atomically. Existing accounts keep other project roles and any stronger role already held in this project. Used, expired and revoked invitations explain how to request a replacement. A removed project cannot be joined.

Accepting the invitation opens the project board directly. Viewers and reviewers need no computer setup. Contributors and maintainers can choose Set up this computer for coding to open their local Code Flow with the server, account name, and project filled in. After confirming their password, Choose repository folder connects their existing clone. A connection link remains available as a fallback for another computer.

A project invitation grants only its project role. It never grants the owner's access, a terminal, or permission to run agents on the server. Those require the existing separate grants. The browser can collaborate on tasks and reviews; a connected computer runs the work its owner starts with their own agent logins. Personal device pairing remains a separate flow.

Choose where work runs

Team collaboration lets the people who work on a project share one team board of tasks and hand work between their computers. One ordinary code-flow instance acts as the team server: teammates reach it over HTTPS through Tailscale or another network and sign in with the existing shared project accounts. Each teammate's own code-flow installation can be linked to that server as a runner ("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 hand-over checkpoint (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.

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.

Vocabulary in this document: team and teammates are people, not the agents' Auto team; a board task is an entry on the team board, not an Auto-team task; a hand-over checkpoint is a published Git bundle, not one of the commit checkpoints under Project → Repository tools → History; a runner is a teammate's own code-flow, not an SSH worker. In the code and the tests the feature is called collab.

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.

Set up the team server

Open Settings → Connections → Share access → Host a team for the guided setup. Choose This computer or a saved SSH server under Server. 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 Set up on this server. Disconnected saved servers offer Connect and set up on this server. Then complete the five steps:

  1. Choose an existing project or create one, and set your name on the board. A local clone on the server is optional.
  2. Choose existing repositories or enter their names, Git URLs and default branches. Internal identifiers are generated automatically.
  3. 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.
  4. Create one-use project invitations so teammates choose their own credentials. Direct account creation and granting existing accounts access remain under Advanced account administration. Other project roles are preserved.
  5. Review the saved configuration and copy connection instructions containing the HTTPS server origin. Passwords and phone pairing links are never included.

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.

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 ~/.codeflow/team-server on the remote machine, separate from ~/.codeflow/ssh-host. Projects, accounts, certificates and team data live in team-server/state; the private owner token and process identity live in team-server/runtime.json. 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.

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. Stop team server 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 Enable automatic startup after setup. Code Flow installs ~/.config/systemd/user/codeflow-team-server.service and verifies both service enablement and user lingering, 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. Check startup status rechecks the actual server configuration; Disable automatic startup disables boot startup without stopping the current server or disabling other user services.

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. Stop team server 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.

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.

Network. Turn on Settings → Connections → Share access, choose Tailscale · access anywhere and choose Set up secure remote access to configure HTTPS, as described in Remote access with Tailscale. 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 access rules, and issue the certificate for this computer's tailnet name with Tailscale HTTPS certificates; the link teammates use carries that name once TLS is configured.

Alternatively, choose Other HTTPS network 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.

Accounts. Create an account for each teammate under Settings → Connections → Share access → People and assign a role per project. Each role includes everything the roles before it may do:

Role On the team board
viewer reads the board, tasks, checkpoint manifests and discussion, and their own inbox
reviewer also comments and @mentions teammates, and records a review (approve or request changes) against a checkpoint
contributor also creates and edits tasks, takes an unowned task, adds decisions, requests a review from a named teammate, proposes Send to agent 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
maintainer also assigns any owner, deletes tasks and checkpoints, defines a project's repositories and cancels any hand-over

Repositories. Under Settings → Connections → Share access → People → Team server, give each project its repository keys: 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 (@owner in a comment reaches the owner), links to the accounts page and, once remote access with HTTPS is on, shows the server's https:// address under Address, without any path: that is what teammates enter when they connect their computers. Never hand out the phone link from Settings → Connections → Share access 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.

Let teammates run tasks on the host

The host owner can enable Settings → Connections → Share access → People → Run teammates’ tasks on this computer 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.

An authorized teammate signs into the shared dashboard, takes a task, and chooses Run on host computer. 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.

The Host queue 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.

Queued work and grants are stored privately in CODEFLOW_HOME/host-execution/queue.json. 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.

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.

The closed API surface is GET /api/host-execution, owner-only PUT /api/host-execution/settings {revision, policy?, concurrency?}, POST /api/host-execution/tasks/:taskId {revision} and POST /api/host-execution/jobs/:jobId/cancel {}. 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.

Give trusted teammates an interactive terminal

Under Settings → Connections → Share access → People → Teammate terminals, 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.

A permitted teammate opens Board → Your host terminals, selects a starting repository and chooses Open terminal. 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.

This grants trusted access to the host's operating-system account. 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.

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.

Grants and up to 500 open/close records are saved privately in CODEFLOW_HOME/terminal-access.json; 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.

The dedicated API is GET/POST /api/team-terminals, owner-only PUT /api/team-terminals/settings {revision, grant}, DELETE /api/team-terminals/:id {}, GET /api/team-terminals/:id/events, and POST /api/team-terminals/:id/input or /resize. 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.

Connect your own computer

Open Settings → Connections → Share access → People → This computer in your own code-flow, enter the server's https:// address (the Address its owner sees under Settings → Connections → Share access → People → Team server), your account's username and password, and a name for this machine (your hostname by default), and choose Connect this computer. 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 runner credential, returned once and kept in the link. Plain http:// 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 <url> 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 <url> (…)": give the server a Tailscale HTTPS certificate for its tailnet name, or trust its certificate on this computer with NODE_EXTRA_CA_CERTS. 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 id).

Use Add team connection in Settings → Connections → Share access → People → This computer for another team. The Team connection selector in Settings and on the board switches between saved servers and This computer’s own board. 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 (?team=<connection id>), so bookmarked task links and tabs for different teams retain their destination.

Connections are stored under CODEFLOW_HOME/team-connections/<connection id>.json (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 team-link.json is automatically moved to team-connections/legacy.json; its runner identity and existing attempt journal are preserved. An unlinked team-link.json still holds the local board's mappings.

Under Settings → Connections → Share access → People → Repositories, map each repository key of each project to a clone on this computer (Use current repository 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.

Disconnect this team 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.

What never leaves this computer: your agent CLI logins, the files copy brings into worktrees (.env 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 boundary each vendor draws.

The team board and tasks

Team in the sidebar (also the command palette entry Team board; #/team, or #/team/project/<id> for one project) shows a column per status, Planned, Working, Blocked, In review and Done, filtered by project, by owner (Mine) and by status, next to your personal inbox. Shared users see the same board under the Team 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.

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 revision. 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, Goal and Acceptance keep Save, Discard and their Unsaved changes mark for as long as your text differs from the task (also once the reload shows a teammate's text), and a refused Depends on change snaps back to the task's list. A board holds at most 500 tasks, and a project at most 50 repository keys.

Status rules: any contributor may set any status, except that Done is refused (409) while an attempt is claimed, running or unknown or a hand-over is still offered, and Blocked 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.

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 superseded: the next attempt starts from a checkpoint, never from one of those worktrees.

An attempt 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 <runner> 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 <name>; 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 unknown, with a reason.

Drafting a task with an agent

On Team, choose Draft with agent, 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. Generate draft 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; Open drafting run shows its details and Stop drafting cancels it.

Review the proposed title, goal (including scope, implementation plan and questions) and acceptance criteria, then choose Use draft in form. Edit those fields and the human owner/reviewer before Create task. Saving opens the task, ready for Build with agents; creating a task never starts a build automatically. The ordinary New task form remains available without an agent. Agent drafting and execution are local-computer controls, unavailable in the shared browser dashboard.

Running a task on your computer

Open the task and choose Build with agents: 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 Continue from the latest checkpoint when one exists. Your code-flow then, in order:

  1. resolves the base commit: the latest checkpoint's commit when continuing (downloaded and imported first, as described under Handing a task over), otherwise the task's base branch, or HEAD of your clone, and checks that the repository can carry checkpoints: one with a submodule, a checkout filter such as Git LFS in .gitattributes, 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");
  2. writes a local attempt record, then claims 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;
  3. starts an ordinary run in a worktree of your clone, on the engine's usual codeflow/<run id>/<worktree> branch (shown as the attempt's branch; only fetched checkpoints land on team/<task id>/… 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 Team task link back to it;
  4. publishes progress 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;
  5. when the run ends, creates a checkpoint if the branch moved past the base (its id is minted here, and the bundle is kept under CODEFLOW_HOME/team-link/bundles/<checkpoint id>.bundle until the server has it), uploads it, and finishes the attempt as finished (the run is done), failed, stopped (a budget or limit stop; resumable) or paused (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 failed when the run was done and otherwise in its paused or stopped state, with the reason "No checkpoint was published: <message>"; the task is released and the work stays on this computer's branch.

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 unknown 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 POST /api/team-link/reconcile; 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.

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 Connection lost; execution status unknown: 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 Recover attempt…, 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. Stop cancels the run (it stays resumable) and records the attempt as paused; Resume 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 <name>; 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. Open run 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).

Discussion, review requests and Send to agent

Every task has a Discussion (comments of up to 4000 characters, 500 per task), Decisions (2000 characters each, 100 per task; they are snapshotted into every checkpoint and read by the next agent), Reviews and a collapsed History of up to 200 audit entries, oldest dropped. @username 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 inbox 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.

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 Send to agent toggle: it is proposed; the task owner, or a maintainer of the project, approves or declines it; an approved instruction is delivered 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 <name> via the team board"), whereas a checkpoint's context reaches the next agent fenced as information from teammates, the way webhook and issue text 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 shared review pages.

Handing a task over

Choose Hand over… 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 Include uncommitted changes 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:

  1. the current attempt must not be claimed, running or unknown: stop it or complete recovery first (409 otherwise);
  2. 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 <branch> 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");
  3. the server records an offer to the teammate and notifies them; the task stays yours, with its status;
  4. the teammate chooses Accept and download on their computer: the bundle is downloaded and imported into their clone of the repository before 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 <state>");
  5. the server then marks the hand-over accepted, makes them the owner and supersedes your paused or stopped attempts;
  6. they continue with Build with agents and Continue from the latest checkpoint, with whatever pattern and agents they choose; the new attempt's base is the checkpoint commit, and the agent reads the checkpoint's context.

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 <base> 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 <id>; it advertises refs/codeflow/team/<other>. 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 refs/codeflow/team/<checkpoint id>, and never touch HEAD, 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.

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 Cancel hand-over while it is offered. Repositories with submodules or checkout filters cannot carry checkpoints and so cannot be used for board tasks; Build with agents refuses them before anything is claimed.

Reviews and integration

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 stale, 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.

To review or integrate on any computer, choose Fetch to this computer… on a checkpoint (contributor or higher, on a linked instance or the team server): the bundle is imported into refs/codeflow/team/<id> and the local branch team/<task id>/<first 8 characters of the checkpoint id> 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.

Storage, limits and boundaries

On the team server everything lives under CODEFLOW_HOME/team/ (mode 0700): board.json (each project's repository keys and its tasks with their attempts, checkpoint manifests, discussion, decisions, instructions, reviews, hand-overs and audit), runners.json (runner ids, names, last-seen times, the address each last connected from and the SHA-256 hashes of their credentials, never the credentials), inbox.json and checkpoints/<checkpoint id>.bundle (mode 0600). Files are written whole through a temporary file and renamed; a corrupt file is moved aside to <name>.corrupt-<time> 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 board.json 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 checkpoints/: every <id>.bundle.<hex>.tmp, and every <id>.bundle that no checkpoint lists as available (not when board.json was set aside as corrupt, so a hand-repaired board keeps its bundles); the removal is logged. On a linked computer, CODEFLOW_HOME/team-connections/<connection id>.json holds each link. CODEFLOW_HOME/team-runners/<connection id>/attempts/<attempt id>.json ties local runs to attempts, and its sibling bundles/ holds pending uploads. Local and migrated legacy records stay in team-link/, filtered by their hub origin.

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.

Boundaries: a runner credential is a bearer token (tr- and 43 characters, shown once at enrolment) bound to one account and one machine. It reaches only /api/team/*: 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 CODEFLOW_TOKEN 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 http:// 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 <local path>. 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 filesystem policies pause starting attempts like other app-managed execution.

Encrypted backups include team/ (the board, the runner registrations with their credential hashes, the inbox and the bundles) and the team-link/ and team-runners/ attempt journals, but leave out team-connections/ and team-link.json, which carries this computer's runner credential, like the other credential stores; a restore of any archive skips it too and lists it under omitted. A restored computer therefore comes up not linked, without repository mappings or defaults: connect it again under Settings → Connections → Share access → People 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 CODEFLOW_HOME at all. Revoke a runner on the team server (Settings → Connections → Share access → People → Runners) if a copy of a connection credential file leaves your control.

API

Paths are absolute; /api/v1/team/* and /api/v1/team-link/* are aliases. Browser sessions (the owner and shared accounts) and runner credentials (Authorization: Bearer tr-…) use the same team routes; the table says who may call. Runner mutations send content-type: application/json (the bundle upload application/octet-stream) and need no Origin header; browser mutations keep the same-origin JSON requirement of shared accounts. Mutations return the updated task; a stale revision 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.

Operation Request Behavior
POST /api/team/runners/connect username, password, name 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.
GET /api/team/me none The caller's identity, project roles and own runners.
GET /api/team/board optional project query 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).
GET /api/team/tasks/:id none The full task (viewer in its project).
POST /api/team/tasks projectId, repository, title, goal, acceptance, optional baseRef, owner, reviewer, collaborators, dependsOn, labels, status Create a task (contributor); 201.
PUT /api/team/tasks/:id revision plus the changed fields Partial save under the status and ownership rules; null clears an optional field.
DELETE /api/team/tasks/:id revision Delete a task (maintainer); {deleted: true}.
POST /api/team/tasks/:id/comments text Comment, with @username mentions (reviewer).
POST /api/team/tasks/:id/decisions text Record a decision (contributor).
POST /api/team/tasks/:id/review-request reviewer, revision Ask a teammate to review (contributor).
POST /api/team/tasks/:id/reviews checkpointId, verdict=approve|request-changes, text, revision Record a review against a checkpoint (reviewer).
POST /api/team/tasks/:id/instructions text Propose a Send to agent instruction (contributor); the task owner's own are approved at once.
POST /api/team/tasks/:id/instructions/:iid action=approve|decline|delivered, optional attemptId Approve or decline (the task owner or a maintainer); delivered is recorded by the attempt's runner.
POST /api/team/tasks/:id/attempts attemptId, runnerId, runnerName, baseCommit, optional fromCheckpointId, revision Claim an attempt (the task owner through their runner, or the server's owner in-process as runner local); idempotent on attemptId; 201. Refused (409) while another attempt is claimed, running or unknown, while a hand-over is offered, and on a Done task.
POST /api/team/attempts/:aid/progress seq, optional runId, the progress fields 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 <name>; they continue it from its latest checkpoint, or a project maintainer reassigns it").
POST /api/team/attempts/:aid/heartbeat empty body Keep the attempt live; returns the approved, undelivered instructions.
POST /api/team/attempts/:aid/finish state, optional head, summary, reason End the attempt as finished, failed, stopped, paused or unknown.
POST /api/team/attempts/:aid/recover revision, reason, confirmedStopped=true 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.
POST /api/team/attempts/:aid/checkpoints optional id, commit, baseCommit, branch, size, sha256, note, requirements, decisions, optional testResults, remaining, changedFiles Register a checkpoint manifest with bundle: "pending" (the attempt's runner); 201; 1.25 MiB. id (32 lowercase hexadecimal characters) becomes the checkpoint's id and ref refs/codeflow/team/<id>; an id already on the board is refused (409), a malformed one 400, and without one the server generates the id.
PUT /api/team/checkpoints/:cid/bundle application/octet-stream body, x-codeflow-sha256 header 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.
GET /api/team/checkpoints/:cid none The checkpoint manifest (viewer).
GET /api/team/checkpoints/:cid/bundle none Download the bundle with content-length and x-codeflow-sha256 (contributor).
DELETE /api/team/checkpoints/:cid none Delete a checkpoint and its bundle (maintainer); {deleted: true}.
POST /api/team/tasks/:id/handoff to, checkpointId, note, revision Offer a hand-over from an available checkpoint of the task (the task owner or a maintainer); refused while an attempt runs.
POST /api/team/tasks/:id/handoff/:hid action=accept|decline|cancel, revision Accept or decline (the recipient); cancel (the sender or a maintainer).
GET /api/team/inbox optional after query The caller's inbox items and unread count.
POST /api/team/inbox/read ids, or all: true Mark the caller's items read; returns {unread}.
GET /api/team/runners none The caller's runners; only the hub owner sees all.
DELETE /api/team/runners/:id none Revoke a runner (its user or the hub owner); {revoked: true}.
PUT /api/team/projects/:id/repositories repositories, revision Define the project's repository keys (maintainer).
PUT /api/team/profile displayName The owner's display name on the board (owner).
GET /api/team/events optional after=<epoch:seq> query Server-sent events for the caller: hello with the epoch and sequence, then change events for the board and tasks in the caller's projects and inbox unread counts; a cursor the server no longer holds gets resync. Closed when the account changes or the runner is revoked, and when 2 MiB of frames wait on the socket.

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 linked is false.

Operation Request Behavior
GET /api/team-link none The link: linked, 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.
POST /api/team-link/connect url, username, password, optional name Enrol this computer: https:// only (plain http:// 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.
DELETE /api/team-link none Revoke the runner on the server (best effort) and forget it here; mappings, defaults and local attempt records stay.
PUT /api/team-link/mappings projectId, repository, path Map a repository key to an absolute folder that is a Git repository.
POST /api/team-link/draft projectId, repository, idea, agent, optional repo, baseRef, agentSettings Start a bounded read-only task-drafting run on this computer; returns {runId}; 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.
POST /api/team-link/tasks/:id/start optional repo, pattern, roles, optional agentSettings, roleSettings, trust, loop (check, setup, maxMinutes, maxSteps), fromCheckpointId Claim an attempt and start the run here; returns {attemptId, runId}; 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).
POST /api/team-link/tasks/:id/stop empty body Cancel the current attempt's run (resumable) and record it as paused.
POST /api/team-link/tasks/:id/resume empty body 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.
POST /api/team-link/tasks/:id/handover to, note, optional includeUncommitted Create or reuse the checkpoint (a retry uploads the kept bundle), then offer the hand-over.
POST /api/team-link/tasks/:id/accept handoffId, optional repo Download and import the checkpoint, then accept the offer.
POST /api/team-link/checkpoints/:id/fetch repo Import a checkpoint and point team/<task id>/<first 8 characters of the checkpoint id> at it; returns {commit, branch, taskId, created}.
GET /api/team-link/attempts none This computer's attempt records: which run belongs to which attempt, and what has been published.
POST /api/team-link/reconcile empty body Run the recovery pass now: settle claims whose answer was lost and retry unacknowledged finishes; returns {attached, finished, removed, unknown, retried}.

In the owner's app the browser's own event stream carries the same board changes as a team topic, and the Team page also polls every 15 seconds; the shared dashboard's Board tab holds one /api/team/events 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.

Validation status

npx tsx --test test/collab-model.test.ts covers the validators and bounds, status transitions, ownership rules, mentions, board summaries and the review state. test/collab-store.test.ts 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. test/collab-api.test.ts 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. test/collab-checkpoints.test.ts creates a bundle from a repository with a base and two commits and imports it into a clone that has the base (ref created, HEAD 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. test/collab-runner.test.ts 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. test/collab-link.test.ts 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. test/e2e/team.e2e.ts 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.

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.

Selecting connections through the owner API

GET /api/team-link/connections lists saved connection IDs and public connection state, including local. POST /api/team-link/connect adds a server and returns its ID. Scope /api/team/* and /api/team-link/* calls with ?teamConnection=<id> or the X-Codeflow-Team header; this selector is consumed locally and is never sent to another server. Downloads use the query form. DELETE /api/team-link?teamConnection=<id> 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 team:<connection id> topics.


Documentation library · Getting started · Local app help

Share a project and get a teammate started

Open a project and choose Share beside its title. The member count opens People and access. Choose View, Review and comment, Contribute, or Manage project, then create and copy an invitation. Existing secure server access is reused. If access is missing, the dialog shows just the network/HTTPS step and keeps the selected project and role. When sharing a project for the first time, its existing repository folders supply portable repository names and generated identifiers; absolute folder paths are not published.

An invited person creates a Code Flow account on that server or signs in to an existing one. Accepting the invitation opens the project board immediately and removes the invitation secret from the address bar. Reviewers and viewers need no computer setup. Invalid, expired, used, and revoked invitations explain how to get a fresh link or sign in to an already joined project.

Contributors can optionally choose Set up this computer for coding on the board. Enter the address of Code Flow running on their computer (the default is http://localhost:4318; use its actual port). The handoff carries only the team address, username, and project in the URL fragment. It never carries an invitation secret, password, or owner credential. Confirm the account password locally, select an existing Git repository folder, and open the same project board. Known local project folders with matching repository names are offered as suggestions. Saving checks the repository; folder mappings remain private to that computer. Git access and cloning remain separate.

A task opened on the shared server presents My computer and Team server execution options. The latter requires a separate owner grant and task ownership. Connecting a computer or accepting an invitation does not grant server execution or terminal access.

People and access shows roles, joined membership, pending invitations, and computer connection status. A connected background computer never marks the person as online. Expand a person for computer names and last connection times (visible to that account and the server owner), plus server execution grants where authorized. The server does not know teammates’ repository mappings, so it does not claim their repositories are ready. Manual accounts, password replacement, host execution grants, and terminals are under Advanced administration. Repository identifiers are generated from names; existing identifiers stay stable and may be edited under advanced repository settings.

The agent collaboration switch is labeled AI team, separate from human project membership. The onboarding browser suite exercises owner invitations, mobile acceptance, reviewer readiness, guided local setup, task execution, permissions, invalid links, and missing secure access. It uses isolated server homes and fake coding agents.

Search documentation