How it works

One loop. Five touchpoints. Zero handoffs.

A walkthrough of a real ticket — from the paragraph you write in Linear to the merged PR in GitHub. Async, on the agent’s clock — not yours.

01You describe

Write a paragraph. Drop a screenshot. Done.

Open a ticket in your PM tool. Type what you want. The agent treats this as the source of truth — including any wireframes you paste in. No spec doc. No handoff.

  • Plain English is fine. Don't think in stories.
  • Paste any image — wireframe, screenshot, sketch.
  • Mention edge cases or leave them out — the agent will ask.
linear.app / specship / SPEC-127
SPEC-127·Todo
Assigned

Add CSV export to invoices table

Customers keep asking how to export filtered invoices to spreadsheet. We need a button on the invoices table that exports the current filter as CSV. Should handle 10k+ rows.

02Agent writes the spec

Acceptance criteria, posted to your ticket.

Within a minute or two, the agent posts back acceptance criteria — clarifying any ambiguity by asking questions. You approve, push back, or rewrite. Nothing moves forward until you do.

  • Criteria are versioned with the ticket.
  • Edit them inline — the agent re-plans.
  • Approve with a 👍 reaction or a comment.
linear.app / specship / SPEC-127
SPEC-127·Writing spec
Assigned

Add CSV export to invoices table

Acceptance criteria · auto-generated
  • User can click 'Export CSV' in the invoice table toolbar
  • CSV includes all rows matching the active filter, not just visible page
  • Streams the file — no server-side timeout for >10k rows
  • Filename format: invoices-{YYYY-MM-DD}.csv
  • Tracked via PostHog event 'invoices.exported' with row count
specship14s ago
Drafted 5 acceptance criteria. One question: should the CSV use ; or , as the delimiter? Defaulting to , unless you say otherwise.
03Tests come first

Failing tests, written before any code.

The agent commits failing tests to a branch. You can read them — they're documentation of intent. Then it writes implementation to make them pass.

  • First commit on the branch: the test file.
  • Tests use your existing runner — jest, vitest, pytest, go test.
  • Coverage reported on every PR — wire it into your CI gate.
app/invoices/export.spec.tsts
import { describe, it, expect } from 'vitest';
import { exportInvoices } from './export';
+describe('exportInvoices', () => {
+ it('exports filtered rows as CSV', async () => {
+ const csv = await exportInvoices({ status: 'paid' });
+ expect(csv).toContain('id,amount,status');
+ });
++
+ it('streams large datasets without timeout', async () => {
+ const stream = exportInvoicesStream({ limit: 50000 });
+ expect(stream).toBeInstanceOf(ReadableStream);
+ });
++
+ it('records analytics event with row count', async () => {
+ await exportInvoices({});
+ expect(posthog.capture).toHaveBeenCalledWith('invoices.exported',
+ expect.objectContaining({ rows: expect.any(Number) }));
+ });
+});
04Then the implementation

A clean PR. Reads like you wrote it.

The agent matches your project's conventions — your file structure, your import order, your naming. Reviewers focus on what changed, not why it looks weird.

  • Picks up your eslint, prettier, biome config.
  • Writes commit messages in your repo's style.
  • Splits commits logically — tests, impl, polish.
github.com / acme / billing-api / pull / 214
Open#214

feat(invoices): CSV export endpoint + UI button

specship/SPEC-127-csv-exportmain
All checks passed
+184 -12
7 files
Author
app/invoices/export.tsts
import { db } from '@/lib/db';
import { posthog } from '@/lib/analytics';
import { toCsv } from '@/lib/csv';
+export async function exportInvoices(filter: InvoiceFilter) {
+ const rows = await db.invoices.findMany({ where: filter });
+ posthog.capture('invoices.exported', { rows: rows.length });
+ return toCsv(rows, ['id', 'amount', 'status', 'created_at']);
+}
05You review

Comment what you'd say to a teammate.

Approve, request changes, or just ask a question. The agent reads every comment on both the ticket and the PR — and responds with code, not chat.

  • Comment 'change the button copy to Download' — gets a new commit.
  • Mark a thread resolved — agent updates the PR description.
  • Approve & merge — the ticket auto-closes with a link to the merge commit.
checks · pr/214
$ specship verify pr/214
→ Linting...
✓ eslint no issues
✓ prettier no issues
✓ typecheck no errors
→ Running tests...
✓ PASS export.spec.ts (3 tests, 84ms)
✓ PASS invoices.spec.ts (12 tests, 240ms)
✓ PASS integration.spec.ts (4 tests, 1.2s)
→ Coverage report
✓ new code 94.2% (above threshold)
· total 91.7% (+0.3% from main)
✓ Ready to merge.
Now in private beta

Stop writing tickets nobody picks up.Start shipping.

Join the waitlist — we’re onboarding a few teams a week. Builders only, no procurement decks.

No credit card · We’ll email you when you’re in · Unsubscribe any time