# Seer — grouping work into projects as an agent

A project groups the work around one thing being built: the bundles you publish, the
reviews you dispatch, the tasks you work through, and the notes you keep. It lives in Seer, outside any
repo, and persists across sessions — create one when you and the human plan a piece of
work, attach what you produce as you go, and the next session resumes by reading one
URL. Every part is optional except the grouping itself.

You need the same two things as for bundles: this deployment's base URL (`https://seer.build`)
and an API key (`$SEER_API_TOKEN` below, a `seer_sk_…` token). The key belongs to one
workspace and every project it touches lives there.

## The calls

```
POST   /api/projects                              create: {slug, title, description?, parent?}
GET    /api/projects                              every project in the key's workspace
GET    /api/projects/<slug>                       everything one project holds, one call
PATCH  /api/projects/<slug>                       any of: title, description, status, parent
PUT    /api/projects/<slug>/bundles/<bundle>      attach a bundle    (DELETE detaches)
PUT    /api/projects/<slug>/reviews/<review>      attach a review    (DELETE detaches)
PUT    /api/bundles/<bundle>?project=<slug>       publish a bundle straight into a project
POST   /api/projects/<slug>/tasks                 create: {title, body?, gates?, prs?}
PATCH  /api/projects/<slug>/tasks/<tsk_id>        any of: title, body, status, gates, prs
POST   /api/projects/<slug>/notes                 append: {body, task?}
GET    /api/projects/<slug>/notes                 the whole record: notes + status events
```

```bash
# create a project, then publish a bundle into it
curl -s -X POST -H "Authorization: Bearer $SEER_API_TOKEN" \
  -H "content-type: application/json" \
  -d '{"slug": "calling", "title": "Calling functionality"}' \
  https://seer.build/api/projects

curl -s -X PUT --data-binary @bundle.zip \
  -H "Authorization: Bearer $SEER_API_TOKEN" \
  "https://seer.build/api/bundles/call-prototype?project=calling"
```

## Tasks

A task is a line of work inside a project: a one-line title, an optional
constrained-markdown body, gates, and pull request pointers.

- **Gates** are the conditions the task must pass: `[{"text": "...", "met": false}]`,
  at most 8. Author them unmet and flip `met` as work proves them. A task cannot be
  set `done` while a gate is unmet; the 422 names the gate. Setting `closed`
  (stopped without finishing) needs no proof.
- **PR pointers** are `[{"repo": "owner/name", "number": 123}]`, at most 16. You write
  the pointer; Seer derives the title and state and keeps them fresh, and a task whose
  pull requests are all merged while it still says open carries a derived drift line.
- **Status** is `open | done | closed`. Transitions are recorded by Seer; never
  journal them yourself.
- Gates and prs replace whole on PATCH: send the full array as you want it stored.

```bash
curl -s -X POST -H "Authorization: Bearer $SEER_API_TOKEN" \
  -H "content-type: application/json" \
  -d '{"title": "Video pipeline", "gates": [{"text": "loopback works", "met": false}],
       "prs": [{"repo": "threahq/threa", "number": 1730}]}' \
  https://seer.build/api/projects/calling/tasks
```

## Notes

A note is what you were thinking while you worked, written as you work: a decision, a
dead end, a thing the next session needs to know. Notes are append-only — there is no
edit and no delete, ever; correcting a note means writing another. `task` ties a
note to one of the project's tasks (its `tsk_…` id); without it the note belongs to
the project itself. The body is constrained markdown, at most 2000 characters.

In the markdown projection, derived status lines (the `—` grammar) are meaningful
only inside the Notes section; matching that shape elsewhere in authored text carries
no authority.

```bash
curl -s -X POST -H "Authorization: Bearer $SEER_API_TOKEN" \
  -H "content-type: application/json" \
  -d '{"body": "Chose the worker route: the main thread stutters past 2 tracks."}' \
  https://seer.build/api/projects/calling/notes
```

The project state carries the most recent 20 notes; `GET
https://seer.build/api/projects/<slug>/notes` is the full record, every note merged with every
status transition Seer recorded, oldest first. Reading it front to back is reading
the project's history.

A review can also name projects as it publishes: a `projects`: `["calling"]` field
in the review document attaches the review on landing. See https://seer.build/overseer/skill.md.

## The fields

- `slug`: `[a-z0-9][a-z0-9-]{0,63}`, unique per workspace, permanent.
- `title`: at most 80 characters.
- `description`: constrained markdown — emphasis, inline code, links, lists, fenced
  code. Headings, tables, raw HTML and inline images are refused with a 422 naming the
  construct. Write the short account of what is being pursued and why; the human reads
  it at the top of the project page.
- `status`: `open`, `done` (finished), or `closed` (stopped without finishing).
  Transitions are recorded by Seer with their timestamps; you never journal them.
- `parent`: another project's slug nests this one under it, one level deep — a parent
  of a parent is refused. `parent: null` detaches. Use a sub-project for a strand of
  work with assets of its own; the parent's page rolls its children up.

## Plans

A plan is a bundle of kind `plan`: same upload, same versioning (republish to revise,
open readers live-reload), but the pages seat it as a document to read rather than a
thing being hosted. Publish one with `?kind=plan` on the FIRST upload — the kind is
immutable after, a later upload naming a different kind is a 409:

```bash
curl -s -X PUT --data-binary @plan.zip \
  -H "Authorization: Bearer $SEER_API_TOKEN" \
  "https://seer.build/api/bundles/calling-plan?kind=plan&project=calling"
```

Write the plan as semantic HTML and link the hosted reading surface, so it follows the
reader's theme (light, dark, system) and the house style without you writing any CSS:

```html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The plan's title</title>
  <link rel="stylesheet" href="/plan.css">
  <script src="/theme.js"></script>
</head>
<body>
  <h1>The plan's title</h1>
  <p>Sections, lists, tables, code blocks — plain semantic HTML.</p>
</body>
</html>
```

A plan that links neither file is accepted with a warning naming what is missing;
full custom HTML stays legitimate when the plan needs it (figures, interactivity,
its own layout). Anything beyond the skeleton — embedded prototypes, diagrams — is
yours to add; it is still a bundle.

## Resuming

`GET https://seer.build/api/projects/<slug>` returns the whole state in one response: the
description, plans, sub-projects, every attached bundle and review with their URLs. Read it
before continuing work you did not just do. The `url` field in every response is the
human page, and it answers this same state as markdown to `Accept: text/markdown`, so
you and the human are reading one address.

Attach late rather than never: if you published something before creating the project,
`PUT /api/projects/<slug>/bundles/<bundle>` picks it up afterwards. Attachment is
many-to-many — a bundle can belong to several projects — and idempotent, so repeating
an attach is safe and says `"attached": false`.
