Developers and agents
The API is the product
Hubtask was built backend first. The specification is written before the code and the code is generated from it; the interface people click is one client of that contract, with no private endpoints and no shortcuts of its own.
One registry
Register once, reachable three ways
A use case is declared in one place with its inputs, its permissions and its side effects. REST routes, MCP tools and automation actions are all projections of that declaration — which is why they cannot fall out of step, and why a check in the build fails if they ever do.
REST
For your scripts and services
Cursor pagination and no page numbers, Idempotency-Key on every mutation, ETag and If-Match for concurrency, and problem documents with a
machine-readable code and parameters instead of prose to regex.
MCP
For agents, inside your instance
Tools named after the use case, input schemas identical to the REST bodies, read-only and destructive hints so a client can ask before acting, resources addressable by URI, and prepared prompts.
RULES
For things that should happen without you
The same catalogue as rule actions, with conditions in an expression language, a dry run, and protection against a rule that triggers itself.
Ask before you guess
An installation describes itself
Installations differ: one has the vector extension and one does not, one has object storage and one writes to a volume, one has an AI provider configured and one has deliberately none. A client that hard-codes those assumptions is a client that breaks on somebody else’s box.
So the server answers what it can do. Which capabilities each item type carries, which fields are queryable and with which comparisons, which layouts exist, whether semantic search is available — all of it read from the installation rather than compiled into the client.
The same principle points the other way: a client must tolerate a field it does not know. That is a binding requirement on every first-party client and the reason a server upgrade does not break an older one.
# What can this installation do?
GET /api/v1/meta/capabilities
# What is degraded right now?
GET /api/v1/meta/health
# A composable query, not a search box
POST /api/v1/items:query
{
"filter": "due_at < now+7d and label = 'release'",
"limit": 50
}Agents
An MCP server that runs where your data already is
Every large task tool now offers an MCP server, and nearly all of them are a hosted endpoint you authorise against their cloud — the agent reads your tasks there. Hubtask’s MCP server is an adapter in the process you started. Nothing leaves the machine unless you configured something for it to leave to.
The security model is the interesting part, and it is the one thing that could not be added later: because authorisation lives in the application layer, an MCP tool call carries no permission logic of its own. An agent holds a scoped credential and is refused precisely what a person with that credential would be refused — and its actions are recorded in the trail as an agent’s.
ai-first.md §1What an agent gets
- Tools The use case catalogue, in snake case, with the preconditions and side effects the registry already knows.
- Resources Hubs, items and views addressable as
hubtask://URIs — a read that is already in the catalogue, reached by URI instead of by argument. - Prompts Prepared and versioned, from the same store the product’s own provider calls read.
- A stream A session identifier that any process can verify without shared state, and the same connection limits a browser’s stream gets.
The rest of the surface
Everything else you would ask for
hubctl
The command line client. Its types are generated from the same specification, it prints a
table for a person and the API’s own payload with --json for a pipe — one
document on standard output and every diagnostic on standard error, so it composes.
Events out
Webhook subscriptions with an HMAC signature, retries and a dead-letter path, carrying published CloudEvents schemas, plus trigger polling endpoints. Generated nodes for n8n and Zapier come with the ecosystem milestone.
SDKs, and the one that exists
The TypeScript client the first-party applications use is generated from the contract, so a rename in the specification becomes a type error in the change that made it rather than in somebody’s production two months later. Published SDKs for TypeScript, Go and Python are an ecosystem milestone and are not out yet — until then the contract generates one for whichever language you need.
Offline conformance
Building your own client? The synchronisation contract is specified — client-assigned
identifiers, an operation id per mutation, a hybrid logical clock per field change,
defined behaviour when access is revoked or a cursor is too old. The conformance runner
that will check an implementation against a real instance, hubctl sync-conformance, arrives with the synchronisation milestone.
Stability
What v1 promises
- The contract is frozen at 1.0 API v1 is stable from the first stable release, with a deprecation process that has been exercised rather than written down.
- Event schemas are versioned and published, so a consumer is not reverse-engineering a payload.
- Migrations are forward only and safe for a rolling update — expand, then contract, never a change to a migration that has run.
- One version for everything The server and every first-party client share a single version number. There is no compatibility matrix to keep in your head.