Use this skill when writing code, scripts, or automations that interact with a Continuous Coordination (CoCo) reference server — the open-source implementation at github.com/continuouscoordination/coco-server, a PostgREST API over PostgreSQL exposing the six CoCo schema entities (actors, teams, team check-ins, goal stories, goal story updates, coordination events). Covers running the stack, the base URL (`http://localhost:2626`), PostgREST query/filter conventions, the auto-generated OpenAPI ...
Scanned 6/18/2026
Install via CLI
openskills install continuouscoordination/coco-skills---
name: coco-api
description: Use this skill when writing code, scripts, or automations that interact with a Continuous Coordination (CoCo) reference server — the open-source implementation at github.com/continuouscoordination/coco-server, a PostgREST API over PostgreSQL exposing the six CoCo schema entities (actors, teams, team check-ins, goal stories, goal story updates, coordination events). Covers running the stack, the base URL (`http://localhost:2626`), PostgREST query/filter conventions, the auto-generated OpenAPI spec, and the create flows for check-ins and goal updates. Trigger any time the user mentions a "CoCo server", "continuous coordination server", `continuouscoordination/coco-server`, PostgREST against the CoCo schema, or wants to read/write coordination data over HTTP — even if they don't say "API".
---
# Continuous Coordination server API
This skill covers writing correct code against a **Continuous Coordination (CoCo) reference server** — the open-source implementation at `https://github.com/continuouscoordination/coco-server`. It assumes the user wants real code (curl, scripts, clients) against the server, not methodology or product answers.
For the *what to write* side — composing good check-ins and goal updates — see the `coco-updates` skill. This skill is *how to move the data*.
## What the server is
The reference server is **[PostgREST](https://postgrest.org) over PostgreSQL** — the REST API is auto-generated from the SQL schema, with **no hand-written application layer**. That single fact drives almost everything below: endpoints, query syntax, and response shapes are all PostgREST conventions, not a bespoke CoCo API. If you know PostgREST, you know this server.
It is **single-tenant with no authentication** by design — meant for tool authors testing against the spec and teams running their own coordination store. There are no tokens, no rate limits, no scopes. Anyone who can reach the port can read and write. To lock it down, the user puts it behind their own gateway/auth proxy.
Default endpoints when running locally:
- **`http://localhost:2626`** — the REST API (PostgREST)
- **`http://localhost:2627`** — Swagger UI (interactive docs over the auto-generated OpenAPI spec)
- **`http://localhost:2628`** — a read-only static viewer listing all six entities
> A deployed server may sit at a different host/port behind a gateway. Treat `localhost:2626` as the local-dev default and parameterize the base URL in anything you write.
## Sources of truth
Two, and your training data is neither:
1. **The CoCo schema repo** — `https://github.com/continuouscoordination/coco-schema` — JSON Schema definitions for the six entities. This is the authoritative shape of the *data*. The server implements a specific schema version (see "Schema version" below); a major schema bump is a major server bump, with no silent multi-version support.
2. **The server's live OpenAPI spec** — auto-generated by PostgREST and browsable at the Swagger UI (`:2627`). This is the authoritative shape of the *running API surface* — every table, view, column, and filterable field, exactly as that server exposes them. Point client generators (openapi-typescript, OpenAPI Generator, etc.) at the live spec rather than committing a snapshot, since it regenerates whenever the schema changes.
Fetch one of these any time the task is non-trivial — exact column names, client generation, typed models, anything touching multiple entities. For a one-off curl against a known entity you can skip the fetch.
## Running the stack
The server ships as a Docker Compose stack (Postgres + PostgREST + Swagger UI + Viewer):
```bash
docker compose up -d # first start pulls images and runs the schema migration
bin/seed # optional: load demo data (teams, actors, a goal story, a week of check-ins)
docker compose down -v # wipe the database back to clean
```
Set `POSTGRES_PASSWORD` in the environment for anything beyond local play. Data persists in the `postgres-data` named volume across restarts; `down -v` removes it.
## The six entities
All live under the base URL as PostgREST resources. Fields below are the essentials — confirm exact columns against the live spec.
| Resource | Key fields |
|---|---|
| `actors` | `id`, `actor_type` (`person` \| `agent`), `name`, `role`, `timezone` |
| `teams` | `id`, `name`, `description`, `member_ids` (text array of actor IDs) |
| `team_checkins` | `id`, `actor_id`, `team_id`, `date`, `previously` (array), `next` (array), `blockers` (array) |
| `goal_stories` | `id`, `title`, `description`, `actor_ids` (array), `team_ids` (array), `parent_id` (self-ref for sub-goals), `timeframe` (`{ start, end }` object) |
| `goal_story_updates` | `id`, `actor_id`, `goal_story_id`, `date`, `title`, `content`, `status` (`on_track` \| `at_risk` \| `off_track` \| `completed` \| `paused`), `progress_percent` (0–100) |
| `coordination_events` | `id`, `actor_id`, `event_type` (`team_checkin` \| `goal_story_update`), `reference_id`, `occurred_at` — **read-only, auto-generated; see below** |
Notes that bite if you miss them:
- **Check-in text fields are arrays, not Markdown blobs.** `previously`, `next`, and `blockers` are each a `text[]` — one element per bullet. Send `["...", "..."]`, not a single newline-joined string.
- **`goal_stories.timeframe` is a nested object** (`{ "start": "2026-01-01", "end": "2026-03-31" }`) on the public view, even though it's stored as two flat columns internally. Write it as the nested object; the view's triggers handle the rest.
- **Sub-goals** hang off a parent via `parent_id`.
## Coordination events are auto-generated — never POST them
Every write to a `team_checkin` or `goal_story_update` (INSERT or a substantive UPDATE) fires a database trigger that creates a matching `coordination_events` row referencing it. No-op updates are ignored, so re-saving identical data doesn't pollute the log.
**Clients never POST to `coordination_events`** — treat it as a read-only activity feed. This is the one place the API diverges from plain CRUD; everything else (actors, teams, check-ins, goal stories, goal updates) is normal POST-to-create / PATCH-to-update REST.
## PostgREST conventions
The query surface is standard PostgREST. The essentials:
| Task | Shape |
|---|---|
| List / filter | `GET /team_checkins?team_id=eq.t-1&date=gte.2026-01-01` |
| Sort, page | `GET /goal_stories?order=created_at.desc&limit=20&offset=20` |
| Read one | `GET /actors?id=eq.p-1` |
| Create | `POST /actors` |
| Update | `PATCH /actors?id=eq.p-1` |
| Delete | `DELETE /actors?id=eq.p-1` |
- **Filters are `column=operator.value`.** Operators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `ilike`, `in`, `is`, and `cs`/`cd` for array contains/contained-by. Full list in the [PostgREST docs](https://postgrest.org/en/stable/api.html).
- **Filtering an array column** (e.g. find teams containing an actor): `GET /teams?member_ids=cs.{p-1}` (contains).
- **IDs** are strings. The server generates a UUID by default, **or you supply your own** (`"id": "p-1"` is valid — the schema's own examples use `p-1`, `t-1`). Useful for deterministic seeding and readable references.
- **`Prefer: return=representation`** on a write echoes the inserted/updated row(s) back; without it you get `201`/`204` and no body.
- **Bulk insert**: POST a JSON array to create many rows in one call.
A reasonable create looks like:
```bash
curl -sX POST http://localhost:2626/actors \
-H 'Content-Type: application/json' \
-H 'Prefer: return=representation' \
-d '{ "id": "p-1", "actor_type": "person", "name": "Quinn Reed", "role": "Product Manager", "timezone": "America/Chicago" }'
```
## Patterns for common tasks
Confirm field details against the live spec; shapes below are the gist.
### Post a team check-in
`POST /team_checkins` with `actor_id`, `team_id`, `date`, and the array fields:
```bash
curl -sX POST http://localhost:2626/team_checkins \
-H 'Content-Type: application/json' \
-d '{
"actor_id": "p-1",
"team_id": "t-1",
"date": "2026-05-22",
"previously": ["Shipped CSV export behind a flag — streams instead of buffering, memory stays flat."],
"next": ["Roll the export flag to 10% and watch error rates."],
"blockers": ["Waiting on sign-off on the proration deferral."]
}'
```
Unlike Steady, check-ins here are a plain CREATE — there's no pre-generation, so you POST a new row. The trigger writes the matching `coordination_events` entry for you.
### Post a goal story update
`POST /goal_story_updates` with `actor_id`, `goal_story_id`, `date`, `title`, `content`, `status`, `progress_percent`:
```bash
curl -sX POST http://localhost:2626/goal_story_updates \
-H 'Content-Type: application/json' \
-d '{
"actor_id": "p-1",
"goal_story_id": "g-1",
"date": "2026-05-22",
"title": "Self-serve onboarding is live",
"content": "New accounts finish setup without a call; day-one activation is up from 48% to 61%.",
"status": "on_track",
"progress_percent": 70
}'
```
`status` is a fixed enum (`on_track`, `at_risk`, `off_track`, `completed`, `paused`) — not a number. `progress_percent` is 0–100.
### Read the activity feed
`GET /coordination_events?order=occurred_at.desc&limit=50` — the chronological log of every check-in and goal update. Join back to the referenced row via `reference_id` + `event_type`.
### Pull a team's check-ins for a date range
`GET /team_checkins?team_id=eq.t-1&date=gte.2026-05-18&date=lte.2026-05-22&order=date.desc`.
### Find a goal's update history
`GET /goal_story_updates?goal_story_id=eq.g-1&order=date.desc`.
## Schema version
The current reference server implements Continuous Coordination schema **1.0.0**. The server's SQL mirrors the JSON Schemas in the schema repo. If you're targeting a specific deployment, check its OpenAPI spec rather than assuming a version.
## Where to point users for docs
- Schema (data shapes, source of truth): `https://github.com/continuouscoordination/coco-schema`
- Server (run it, REST conventions): `https://github.com/continuouscoordination/coco-server`
- Live API docs for a running server: Swagger UI at `:2627`
- PostgREST reference (filters, query syntax): `https://postgrest.org/en/stable/api.html`
- The methodology: `https://continuouscoordination.org`
## A note on Steady
[Steady](https://runsteady.com) is the commercial Continuous Coordination platform. It implements the same methodology but exposes a **different, authenticated REST API** (tokens, rate limits, its own field names — `previous`/`intentions`, `body`/`confidence`). If the user is writing against Steady rather than a self-hosted CoCo server, use the `steady-api` / `steady-cli` skills instead. The `coco-updates` skill covers writing content that targets *either*.
No comments yet. Be the first to comment!