Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions BUILD_INSTRUCTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ A local-first coordination layer for people and coding agents working in separat
- **There is no web dashboard**, and no web UI for teams, invites, settings, onboarding, analytics, or a live feed. The multi-tenant backend is untouched: workspaces, memberships, invites, pairing codes, roles, RLS, presence, and billing all still exist in `apps/service` and in the SQL migrations. They are reached from the CLI and the HTTP API. "Deleted" applies to the browser UI, never to the service.
- **There is no editor extension.** Editors and agents integrate through MCP, which is the one integration contract.

**Product-scope decision (2026-08-01): Crosscode has no standalone solo use case.** The whole point is coordinating concurrent editors on a repo. One person running one agent alone has nothing to coordinate with, and shouldn't be the product's framing or free-tier target. The one legitimate non-team case is **one person running multiple concurrent agents** (e.g. Claude in one worktree, Codex in another, same repo) — that's still real multi-party coordination, just intra-person. Design free-tier/messaging around "coordinate concurrent editors, human or agent," not "useful even completely alone."
**Product-scope decision (2026-08-01, reaffirmed and sharpened 2026-08-04): Crosscode is for shared projects whose team members all run coding agents.** That is the audience — not "anyone with agents."

Two situations count, and only these two:

1. **Several people on one project, all of them running agents.** The primary case, and what every feature is shaped for: invites, roles, seats, presence, claims, handoffs, per-workspace autonomy policy. This is why the product exists.
2. **One person working alone *right now* on a project they share with others**, whose teammates simply aren't coding today. Still the same case — the repository is shared, their agents will land work on it again, and the proposals waiting on return are exactly what Crosscode makes safe.

**Explicitly out of scope:** a repository only one person will ever touch. There is nothing to coordinate with, and plain Git is the better tool. Do not frame the product, the free tier, or the marketing site around solo use — "you don't need a team" is the wrong message, and was briefly live on the landing page in error (corrected 2026-08-04).

One person running several of their *own* agents in parallel worktrees is a real coordination problem, but it is not the wedge and must not lead the messaging: it converts poorly into the team product and describes a user who can often get by without us. Design free tier and messaging around "your team's agents are colliding," not "useful even completely alone."

**Fundamental rules** (unchanged, non-negotiable):

Expand Down Expand Up @@ -197,7 +206,7 @@ ever stop working.
**Billing note:** at $2.50/mo Stripe takes $0.30 + 2.9% ≈ 15% of revenue; at $25/yr it is
~4%. Annual billing is not a nice-to-have at these price points.

**Design intent:** the free→paid wall should be hit naturally through wanting to collaborate — free tier should be good enough that a solo multi-agent user (see the solo-use decision above) likes it, and the first real friction point is inviting teammate #2 or wanting a conflict to auto-resolve, not an artificial cap.
**Design intent:** the free tier should comfortably fit a real small team (see the product-scope decision above) rather than tease them into upgrading — 5 seats is a whole team, not a trial. The first real friction point should be growing past that team, wanting a longer history to look back through, or wanting conflicts to auto-resolve, never an artificial cap.

**Exit criteria:** Stripe account exists and is wired to workspace creation/upgrade; each tier's caps are enforced server-side (not just UI-hidden); student verification flow works; downgrade/cancellation doesn't destroy workspace data.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The important part: those incoming edits are **never written to your files autom

Everything stays ordinary Git. Crosscode doesn't replace your editor, your agent, your Git host, your branches, your staging area, or your commits — and if you turn it off, your repository is unchanged.

**Who it's for.** Anyone running more than one coding agent against one codebase, or a small team whose agents keep colliding on the same files. Human-only teams can use it too, but the review-before-it-lands workflow pays off most once agents are in the mix.
**Who it's for.** Teams sharing one codebase where the people are all running coding agents. That is the case Crosscode is built for, and the one it is worth setting up for. It keeps working when you are the only person online that day — the project is still shared, and your teammates' agents will land work on it again — but a repository only you will ever touch has nothing to coordinate with, and plain Git is the better tool for it. Human-only teams can use it too, though the review-before-it-lands workflow pays off most once agents are in the mix.

**There is no web app.** Everything you do day to day — signing in, claiming work, reviewing proposals, accepting, publishing — is a `crosscode` command or an MCP tool call your agent makes against your local daemon. The website is only a landing page, sign-up/sign-in, and these docs.

Expand Down
29 changes: 29 additions & 0 deletions apps/docs-site/api/[...path].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import { createServerlessHandler } from "@crosscode/service/serverless";

/**
* The coordination service, served from the same project as the marketing site.
*
* Everything under /api/* is routed here by vercel.json and handed to the service's own
* router, so there is exactly one implementation of routing, auth, and rate limiting
* rather than a web copy and a self-hosted copy that drift apart. `pnpm service` remains
* the persistent-process entrypoint self-hosters run.
*
* The daemon addresses the service by base URL and appends `/v1/...`, so it needs a base
* of `https://<host>/api` here. That is what DEFAULT_SERVICE_URL in
* apps/daemon/src/hosted.ts must point at.
*
* Node runtime, not edge: the service uses node-postgres and node:crypto.
*/
export const config = { runtime: "nodejs" };

// Built on first request and reused while the instance stays warm, so the Postgres pool
// and the Supabase JWKS fetch are not paid for on every invocation.
const handler = createServerlessHandler();

export default async function (request: IncomingMessage, response: ServerResponse): Promise<void> {
// The platform routes /api/v1/foo here; the router matches on /v1/foo. Strip the prefix
// once, at the edge of the adapter, so no route pattern has to know it is behind /api.
if (request.url) request.url = request.url.replace(/^\/api(?=\/|$)/, "") || "/";
await handler(request, response);
}
38 changes: 19 additions & 19 deletions apps/docs-site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,20 @@
<div class="inner hero-grid">
<div class="hero-copy reveal">
<span class="eyebrow">Pre-1.0 &middot; Open source &middot; MCP-native</span>
<h1>Your coding agents are overwriting each other. Crosscode stops that.</h1>
<h1>Your team is all running coding agents on one repo. They are overwriting each other.</h1>
<p class="subtitle">
Run Claude in one worktree and Codex in another and they will quietly
clobber each other's edits. Crosscode gives each checkout a small
background daemon that notices every edit once it has settled and shares
it with the others. Nothing is ever written to your files behind your back
Once every person on a project has an agent editing code, the collisions
stop being occasional. Crosscode gives each teammate's checkout a small
background daemon that notices every edit as it settles and shares it with
everyone else. Nothing is ever written to your files behind your back
&mdash; each change arrives as a proposal you accept or reject, like a pull
request that takes seconds instead of a round trip through your Git host.
</p>
<div class="cta-row">
<a class="cta" href="#install">Set it up with one prompt</a>
<a class="cta secondary" href="#pricing">See pricing</a>
</div>
<p class="hero-microcopy"><strong>You don't need a team.</strong> One person running two agents is already two editors on one repo &mdash; that's the case Crosscode was built for. Free forever for that, and free forever if you self-host.</p>
<p class="hero-microcopy"><strong>Built for shared projects.</strong> It keeps working when you're the only one online &mdash; your teammates' agents are still going to land work on this repo, and Crosscode is what makes that safe when they do. Free for small teams, and free forever if you self-host.</p>
</div>

<div class="hero-visual reveal">
Expand Down Expand Up @@ -82,8 +82,8 @@ <h1>Your coding agents are overwriting each other. Crosscode stops that.</h1>
<section id="compare" class="alt">
<div class="inner">
<div class="section-heading reveal">
<h2>What you're probably doing now &mdash; and what it costs you</h2>
<p>Everyone running more than one agent has already invented a workaround. Here's how each one actually plays out.</p>
<h2>What your team is probably doing now &mdash; and what it costs you</h2>
<p>Every team whose agents collide has already invented a workaround. Here's how each one actually plays out.</p>
</div>

<div class="compare-table reveal">
Expand All @@ -93,7 +93,7 @@ <h2>What you're probably doing now &mdash; and what it costs you</h2>
<div>With Crosscode</div>
</div>
<div class="compare-row">
<div class="compare-now">Point both agents at one checkout</div>
<div class="compare-now">Everyone points their agent at the same branch</div>
<div class="compare-pain">Whoever writes last wins. You find out when the tests fail, or later.</div>
<div class="compare-fix">An edit is never applied on top of a newer local change. Stale writes are refused, not merged.</div>
</div>
Expand All @@ -108,7 +108,7 @@ <h2>What you're probably doing now &mdash; and what it costs you</h2>
<div class="compare-fix">Review happens locally, in your terminal or through your agent, in seconds. Publish to a real branch when you're ready.</div>
</div>
<div class="compare-row">
<div class="compare-now">Tell the agents which files to avoid</div>
<div class="compare-now">Tell everyone which files to stay out of</div>
<div class="compare-pain">Works until one of them ignores you, which they do.</div>
<div class="compare-fix">Claims and live presence make it a fact the other agent can query, not an instruction it might drop.</div>
</div>
Expand Down Expand Up @@ -136,9 +136,9 @@ <h2>Use cases</h2>
<div class="usecase-grid stagger">
<div class="usecase-card usecase-card--featured reveal">
<div class="usecase-card-main">
<h3>Run multiple agents on one repo, in parallel</h3>
<h3>Everyone's agents on one repo, at the same time</h3>
<ul class="usecase-card-list">
<li>Claude Code and Codex CLI can work the same checkout without clobbering each other's edits</li>
<li>Your Claude Code and a teammate's Codex CLI can work the same branch without clobbering each other</li>
<li>Every settled change becomes a durable transaction the instant it lands</li>
<li>Ask "who else is working on this repo right now?" and get a real answer</li>
</ul>
Expand Down Expand Up @@ -236,8 +236,8 @@ <h3>This website <span class="badge soon">Going deeper</span></h3>
<section id="benefits" class="alt">
<div class="inner">
<div class="section-heading reveal">
<h2>Why teams running multiple agents reach for Crosscode</h2>
<p>Once more than one agent (or person) touches a repo at the same time, coordination stops being optional.</p>
<h2>Why teams whose agents collide reach for Crosscode</h2>
<p>Once more than one person on a project has an agent editing code, coordination stops being optional.</p>
</div>

<div class="benefit-grid stagger">
Expand Down Expand Up @@ -279,9 +279,9 @@ <h3>Give your agent real situational awareness</h3>
<div class="section-heading reveal">
<h2>Pricing</h2>
<p>
The free plan is meant to be the one most people never leave. Unlimited AI review,
unlimited repos, auto-apply, and up to 5 people &mdash; and if you host it yourself,
everything is free forever with no limits at all.
The free plan is meant to cover a real team, not tease you into upgrading. Up to
5 people, unlimited repos, unlimited AI review, auto-apply &mdash; and if you host
it yourself, everything is free forever with no limits at all.
</p>
</div>

Expand Down Expand Up @@ -625,8 +625,8 @@ <h2>Questions people ask before installing</h2>
<p>Yes. The CLI works for human-only teams too, though the proposal-review workflow matters most once agents are in the mix.</p>
</details>
<details class="faq-item reveal">
<summary>Do I need a team to get anything out of this?</summary>
<p>No, and this is the most common misread. One person running two agents in two worktrees is already two editors on one repo, which is exactly the problem Crosscode solves. Everything works with a single account and no one to invite. Teammates are something you add later, not a prerequisite.</p>
<summary>What if I'm the only one working on it today?</summary>
<p>That's still the case Crosscode is for, as long as the project is shared. Your teammates' agents will land work on this repo again, and the proposals waiting for you when they do are exactly what Crosscode exists to make safe. What it is <em>not</em> built for is a project only you will ever touch &mdash; there is nothing to coordinate with, and you should just use Git.</p>
</details>
<details class="faq-item reveal">
<summary>Does my source code get sent to an AI provider?</summary>
Expand Down
3 changes: 2 additions & 1 deletion apps/docs-site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"preview": "vite preview"
},
"dependencies": {
"@supabase/supabase-js": "^2.58.0"
"@supabase/supabase-js": "^2.58.0",
"@crosscode/service": "workspace:*"
},
"devDependencies": {
"markdown-it": "^14.1.0",
Expand Down
11 changes: 11 additions & 0 deletions apps/docs-site/vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"rewrites": [
{ "source": "/api/(.*)", "destination": "/api/[...path]" }
],
"functions": {
"api/[...path].ts": {
"maxDuration": 30
}
}
}
24 changes: 24 additions & 0 deletions apps/service/migrations/012_rate_limits.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-- Durable rate-limit counters.
--
-- The in-process FixedWindowRateLimiter is correct in a persistent deployment, where one
-- process is the whole service. On a function platform every instance starts cold and
-- shares nothing, so an in-memory counter silently becomes "N x the limit" for N warm
-- instances. For courtesy limits that is a degradation; for POST /v1/pairing-codes/claim
-- it is a security regression, because that per-IP throttle is the only thing standing
-- between an attacker and brute-forcing a 40-bit code space.
--
-- So limits whose job is defence live here, shared across instances. Limits whose job is
-- politeness stay in memory rather than paying a database round-trip on every request.

CREATE TABLE IF NOT EXISTS rate_limits (
bucket text PRIMARY KEY,
window_start timestamptz NOT NULL DEFAULT now(),
count integer NOT NULL DEFAULT 0 CHECK (count >= 0)
);

-- Lets the sweep find expired rows without scanning the whole table.
CREATE INDEX IF NOT EXISTS rate_limits_window_start_idx ON rate_limits (window_start);

-- Service-internal bookkeeping: no member ever selects from this. RLS on with no policy
-- denies every non-service role by default, which is exactly the intent.
ALTER TABLE rate_limits ENABLE ROW LEVEL SECURITY;
5 changes: 5 additions & 0 deletions apps/service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,10 @@
"devDependencies": {
"@types/pg": "^8.20.3",
"@types/ws": "^8.18.1"
},
"exports": {
".": "./src/http.ts",
"./serverless": "./src/serverless.ts",
"./store": "./src/store.ts"
}
}
Loading
Loading