Projects
A project is the durable home for a codebase across everything you do in partyline — its machines, runs, context threads, and the standing guardrails your agents build within. It's the join key that ties a repo on your laptop to the runs on the board and the shared memory your agents read.
The label
Every project has a label — a short slug (e.g. checkout-web) that machines advertise and runs point at. It's the key that joins machines, runs, and threads, so the board knows which machine can build which project.
$ ptln projectlists your team's projects. Create one:
$ ptln project new "checkout-web" --team acmeInspect one:
$ ptln project show <id>It names the project's id, the repo it's keyed to (or says plainly that none is recorded), and the context thread it resolves to — then lists its promoted facts (its canon). Those first three lines exist because nothing else showed them: when a repo resolved to the wrong thread, or to none, no command would tell you, and a wrong pin turned into a long hunt.
Set up the repo you're already in
ptln project new makes a project with nothing attached to it. If you're standing in the repo the project is for, one command does the whole setup:
$ ptln project setupThe label defaults to the directory's name. It creates the project, gives it a context thread and pins that in .partyline.json (check that file in — teammates who pull land in the same thread), and registers the directory on this machine so work can be built here.
Your LLM can do the same thing without leaving the session: the create_project MCP tool runs exactly these steps, and planning works immediately afterwards in that same session — no restart. It's what to reach for when planning tells you this repo isn't a project yet.
Registering the directory is a grant, not bookkeeping. It declares this directory available to your team, and agents your teammates dispatch may build in it unattended, with no further prompt on this machine. That's the same consent ptln daemon add-project gives, said out loud. Withdraw it any time — the project itself is untouched:
$ ptln daemon remove-project checkout-webTwo refusals worth knowing, both about identity: the directory must be a git repo with an origin remote (a local path means a different repo on someone else's machine, so it can't key a project), and a repo your org already has a project for is adopted, never duplicated — you get the existing label back.
partyline.sh/projects lists your team's projects; open one to manage its display name, description, repository, and everything else on this page. + New project has three doors: pick a repo through the connected GitHub App, pick one a machine already has, or name a project that is nowhere yet — no repo attached, optionally scaffolding a fresh GitHub repo as you go. A repo-less project is useful as an umbrella for other projects, or as a pure planning container. A label one of your machines already advertises shows up there as a one-click adopt suggestion.
Pointing a project at your code
A project needs a git repository on a machine that runs partyline. There are two ways to get one, and GitHub is not required.
A local directory. Any git repo already on one of your machines can be a project — it doesn't need a remote, and the code never leaves that machine. From the machine itself:
$ ptln daemon add-project checkout-web ~/dev/checkout-webOr pick it in the browser: Settings → Integrations → Repository access → Local directory lists the repositories each of your machines found, and binding one registers it exactly as the command above would. See what a machine offers with:
$ ptln daemon reposEach machine scans your home directory up to three levels deep and skips hidden directories, dependency and build output (node_modules, vendor, dist, build, target, venv, …), partyline's own managed clones, and linked git worktrees — so the throwaway directories that builds create never crowd out your real repositories.
Only you can bind a directory on your machine, even inside a team: it's your computer. partyline never receives the path — the machine advertises an opaque handle plus the repo's name, and resolves that handle back to a directory itself. A handle it doesn't recognise is refused, so the web can only ever name a folder your machine already offered.
A repository the machine doesn't have yet. A machine also advertises the directories it could put code in — every place you already keep repos, its registered scan roots, and always ~/partyline as a fallback, so a fresh box is never a dead end. Pick one in the browser and the machine clones the repo there itself, reporting cloning → registering → ready as it goes. See what it offers with:
$ ptln daemon destinationsThe clone uses that machine's own git credentials (its SSH key, gh auth login, or credential helper) — nothing travels from partyline. If the machine can't reach the remote, the failure says so and names the fix to run there. It never overwrites: if the target directory already holds the repo, it's registered as-is with no clone; if it holds anything else, the assignment is refused and names the directory.
A GitHub repository. Connect the GitHub App under the same settings page to create repos for new projects and let machines clone on demand. See security for what that grant covers.
Putting a project on another machine
A project's page has an Add a machine panel with both doors. Pick the machine, then either:
- Clone it onto a machine — choose one of the destinations that machine advertises (its default workspace
~/partyline, any registered scan root, or a folder your repos already live in). The machine does the clone itself. Needs a repo URL on the project; a repo-less project shows no clone option, because there is nothing to clone. - It's already on a machine — pick a checkout the machine already has, exactly like the settings picker above.
Either way you never send a path: the picker lists only what the machine volunteered, as an opaque handle plus display text. To see the same list from the machine:
$ ptln daemon destinationsA machine offering none is running a version that predates the feature — run ptln update on it and wait for its next check-in.
The panel then follows the work live — queued (waiting for the machine's next check-in, or for an offline one to reconnect) → cloning (minutes, for a large repository) → registering → ready, at which point the machine appears under Machines on the project's page — and in the fleet — and the project is runnable there. A failure shows the machine's own reason: a repository it can't authenticate to names the repo and what to fix on that machine.
Umbrella projects
A project can contain other projects — one level deep. On a repo project's page, set Part of to put it inside an umbrella; the umbrella's page lists its repos under Repos in this project.
The point is planning: a planning session on any repo inside an umbrella plans into the umbrella's single context thread — one memory and one plan for a multi-repo product, instead of a plan per repo. Repo-less projects (created with + New project) are the natural umbrellas.
Tasks still know where they build. In an umbrella, the Planning agent assigns each task the repo it builds in, and Start/Promote pre-select that repo — so a cross-repo plan still dispatches each task to the right codebase.
The thread a project resolves to
A project has one context thread it resolves to. Planning agent defaults into it, and it's created automatically the first time you plan — titled after the project and visible to the whole team. (The reverse isn't true: a thread you make by hand with ptln thread new belongs to no project until you point one at it.)
Change which thread a project resolves to from the thread's own page — the project select there attaches it, or detaches it with "— none —", and only the thread's owner can. From the CLI:
$ ptln thread use <thread-id> <project-id>ptln thread attach is a different link, and this is worth reading twice. attach grants the thread canon inheritance — it starts reading that project's promoted facts. It does not change which thread the project resolves to. The two are stored separately and neither writes the other, so attach can print ✓ while every checkout still resolves somewhere else. use is the one that decides identity; ptln project show <id> names both ends so you can check rather than assume.
Guardrails your agents build within
A project carries standing guidance — your stack, your conventions, what "done" means — that's injected into every run in that project. Set it up once and every agent that builds a task reads it, so you're not restating "use server components, always add a migration, never touch the auth module" on each task.
You can type that document yourself, or have an agent write it with you: Set up with an agent (Refine with an agent once there's something there) picks one of the project's machines, opens a conversation with an agent standing in the repo — grounded and read-only — and Finalize writes the agreed document back to the project. It's a party in setup mode, so it reads and behaves like any other Party.
There's also a planning instructions field that steers the interview for every plan made in the project — appended to the default prompt, never replacing it.
Base branch
Every run forks from and every PR targets the project's base branch — one setting, read for both, so a run can never build off one branch and open its PR against another. Leave it blank and runs root at the repository's own default branch (origin/HEAD) — usually main, but whatever that repo actually says. Point it at develop (or a release branch) in project settings and the whole pipeline follows.
The branch must exist on the remote: a run against a base the remote doesn't have fails loudly with that reason rather than silently falling back to main — building against the wrong base is the kind of mistake you want stopped, not papered over. The setting needs CLI ≥ 0.15.0 on the daemon — the settings page says which of your machines qualify. An older one simply never learns the key and keeps rooting at the repo's default branch, which is the behaviour the setting replaces, so nothing breaks.
Engine and model, per phase
Project settings pin an engine and model for each phase — planning (describe), building (crank), review, and consult (answering a peer). Engines are a closed set (claude · codex · gemini · opencode · goose · antigravity); models are free-form and belong to the engine you picked. Blank = the machine's registered default (ptln daemon add-project --engine), and a per-run override on Start beats both.
Antigravity is interactive/planning-only — it can't run headless build or review jobs, so those selects don't offer it. The other limits (codex needs bash, gemini needs a trusted project dir, daemons need CLI ≥ 0.10.0) live in which engine builds.
Projects and shared context
Projects are the substrate for Context Threads: a project resolves to a thread, and durable facts that thread accumulates can graduate into the project's canon, so they outlive any single thread. Deleting a project removes the definition only — machines keep advertising the label, and graduated context survives.
Next: Context Threads · Build & Ship · Planning agent.