# A shared graph for your data, tools, and agents.

`yak` is a command line, and `@yaks` a set of open-source TypeScript packages, for one graph that you and your agents both read and write.

## A task is an entity

Say you're starting a business, and agents build the product. An entity is an id and the components it carries. `task new` writes one with `doc{title}` and `task{}`, and the graph gives it a number.

```sh
# A task for an agent: the sign-up page
yak task new 'Add the sign-up page'
```

## A link is an entity too

Some work only a person can do, such as signing up with a payment processor, so that task is assigned to you. An edge ties one entity to another: this one says the checkout requires it.

```sh
# A task only you can do, assigned to you
yak task new 'Sign up for payments' --assignee U-1
# The checkout, for an agent to build
yak task new 'Build the checkout'
# An edge: the checkout requires the payments sign-up
yak task update T-4 --requires T-3
```

## Your agent calls the same tools

Every `yak` command is also an MCP tool, served at `/mcp` by `yak serve`. An agent finishes the sign-up page and says so, and its writes carry its own id.

```mcp
# The agent says what it did, on the task
comment_new {"target": "T-2", "body": "The sign-up page is up at /signup, with tests."}
# Then marks the task done
task_update {"task": "T-2", "status": "done"}
```

## One query finds them

What's left is the payments sign-up only you can do, and the checkout that waits on it. The same query grammar reads the graph in the terminal, over MCP and in the browser.

```sh
# Every open task, with its doc
yak graph query '.task.status=open ?doc'
```

## This page is a graph

Its sections, its files and each command you type are entities in the graph running in this tab, and the page draws itself from them. Change this section and it redraws. Reloading starts over.

```sh
# The page's own files, which are entities too
yak graph query '.file ?file'
# Retitle this section, and the page redraws it
yak graph apply 525ab3f6-bdc3-48a6-b2f3-e88fa2d06a1b '.doc.title="This page is a graph you can change"'
```

## A write is a list of bundles, applied in one transaction

A bundle is one entity's components, and a write is a list of them. Here your agent writes you a letter: one bundle, its `doc` the words, `mail` the task it is about and `deliver` who it goes to.

`apply()` takes the list through the phases below, and the rules and checks of every package the graph loads run inside them. As you scroll past each, it does its work on the letter: the short ids become eids, the alias is given one, a rule fills in the sender, and after the commit an effect hands the letter to a mail service. The phases in the box are one transaction: the batch is stored whole at commit, or not at all.

```mcp
# One bundle: a letter to you about T-3
graph_apply {"bundles": [{"entity": {"eid": "$letter"}, "doc": {"title": "Can you sign up for payments?", "body": "The checkout can't be built until T-3 is done."}, "mail": {"target": "T-3"}, "deliver": {"to": "U-1"}}]}
```

## Every interface reaches the same graph

The terminal, your agents over MCP and a page in the browser call the same tools on one graph. Scroll, and each makes its own change to the graph drawn above. `--host` points the same commands at another machine, or at yaks.app once you run `yak auth yaks.app`.

### In the browser

You opened the payment account today, and tick it off in the browse app `yak serve` draws at `/`.

```web
task_update {"task": "T-3", "status": "done"}
```

### Over MCP

The checkout no longer waits on anything, so your agent finishes it.

```mcp
task_update {"task": "T-4", "status": "done"}
```

### In a terminal

The tests fail on main, so you file the fix and give it to your agent.

```sh
yak task new 'Fix the failing build' --assignee N-5
```

## Rules change a write as it is made, and effects do what it leaves

You don't write code that watches the graph. A **rule** is a query a vocabulary declares, and the graph runs it inside every write, whichever door the write came through: what it matches, it changes before the write is stored, so nothing ever reads the graph without it. An **effect** is work a write leaves behind. The commit records it in the same transaction, so it can't be lost, and after the commit it runs on its own, tried again until it succeeds.

### Your agent asks you

Fixing the build, your agent needs an answer only you can give, and asks.

```mcp
decision_new {"question": "Which payments key should the build use?", "choices": [{"label": "The test key", "description": "The build never charges a card."}, {"label": "The live key", "description": "The build checks the live account."}], "recommended": "The test key", "assignee": "U-1"}
```

### Your inbox writes you a letter

Your agent says the build requires your answer. A question that holds up work is one `@yaks/inbox` mails you: it writes you a letter whose text is the question, each choice with its line, and how to answer by replying.

```mcp
task_update {"task": "T-7", "requires": ["T-8"]}
```

### An effect hands it to the mail service

`@yaks/mail` declares an effect for every letter written: hand it to the mail service, and record what happened. The commit owed it, so it runs after the write, on its own.

### The mail service is busy

The mail service refuses the letter for now. That is the far end's answer: nothing in the graph or in the effect failed, and the letter is kept as it was written.

### The effect tries again on its own

The effect waits as long as the mail service asked, then hands the letter over again. Nobody runs it again: the work it owes stays in the graph until it is done.

### The mail service takes it

This time the mail service takes the letter, and the effect records that it was sent.

### You answer by replying

You reply with the choice you want. `@yaks/inbox` reads the reply as a comment on the question and records your answer, and `@yaks/task`'s rule finishes the question in the same write.

## What one agent learns, every agent after it knows

An agent's context is gone when its session ends, so what it learns is kept in the graph. A **memory** marks words a person said, verbatim, where they said them. A **persona** is the instructions an agent wears: it contains documents and memories by edges, and every session that wears it starts with all of them, after the personas it is built on. A **topic** holds what is known about one subject the same way. A session opened on a topic wears one persona, the oracle, and starts with the topic's tree, so it answers from what the topic holds.

### You say it once

Answering the question, you say why.

```web
comment_new {"target": "T-8", "body": "Never put the live key in CI: it charges real cards."}
```

### Your agent keeps your words

It marks your comment as a memory, with a line of context. The words stay yours, where you wrote them, and `memory_recall` finds them again.

```mcp
memory_save {"on": "C-9", "context": "Which payments key the build uses"}
```

### Its persona carries them

It files the memory in the persona it wears.

```mcp
graph_apply {"q": "$filed .edge.from=N-5 .edge.to=C-9 .contains"}
```

### The next agent starts with them

A new session wearing the persona is given its text and everything it contains, so the next agent knows to keep the live key out of CI without being told.

## yak is a command line for the tools your graph declares

A config names a SQLite file and a list of plugins. Each plugin is an `@yaks` package, and every tool it declares is a `yak` command and an MCP tool.

- **Every tool is a command.** Its arguments and help come from the tool's input schema, so a new tool needs no new release of yak.
- **No server needed.** A command opens the graph in its own process, runs one tool and exits.
- **Every call is recorded.** A call from you and a call from an agent go through the same checks, rules and effects, and each is kept in the graph.
- **`yak serve` answers HTTP.** The browse app at `/`, the tools for agents at `/mcp`, and `/query` and `/apply` for programs, on this machine only.
- **Your agents join it.** `yak hooks install` makes each Claude Code session an entity in the graph, told its claims when it starts. Any MCP client can call the tools at `/mcp`.
- **Other graphs too.** `--config` opens the graph another config names, and `--host` calls the graph on another machine.

## yaks.app hosts web apps on the same packages

yaks.app builds, hosts and shares web apps. You ask Claude or ChatGPT for an app, and yaks.app keeps it online at its own address, with its data in a graph made of these packages.

- **One toolkit in two places.** On your machine, `yak` keeps a graph in a SQLite file. On yaks.app, the same `@yaks/graph` keeps each app's data in a Cloudflare Durable Object.
- **Your assistant builds the app.** Add yaks.app to Claude or ChatGPT and ask for what you need. It writes the app, and yaks.app serves it at an address like `yourname.yaks.app/recipes`.
- **The same `yak` reaches it.** `yak auth yaks.app` signs you in. Then `yak app_list` lists your apps and `yak app_errors --app recipes` shows what broke in one, from the command line that runs your own graph.
- **An app's commands run in your terminal.** A yaks app can declare commands of its own, and `yak <app> <command>` runs them as you.
- **Your graph passes on what it doesn't have.** A command your own graph doesn't declare goes to yaks.app, so `yak app_list` works on a machine that keeps a graph of its own.

## Get set up on yaks.app

Type your email address, and yaks.app's Operator writes to you. Its letter has a code and a link that signs you in. Reply to it, and the Operator sets you up: `yak` installed and signed in, yaks.app added to Claude or ChatGPT, and your first app online.

This is the one thing on this page that leaves the tab. What you type becomes a bundle in the graph here and goes through `apply()` like everything above; its effect then posts your address to yaks.app's sign-in door, the one yaks.app's own sign-in uses. Nothing more is sent until you reply.

## Install yak, then start your graph

The installer runs on [Deno](https://deno.com) and puts `yak` on your PATH, at one release with every package it loads.

### Install yak

```sh
deno run -A jsr:@yaks/cli/install
```

It installs the newest release at least a day old, since Deno waits a day for a new one. To update to the newest, even one published today:

```sh
deno run -A --minimum-dependency-age=0 --reload=jsr:@yaks/cli jsr:@yaks/cli/install
```

### Start your graph

```sh
yak init
```

It writes `~/.yak/yak.json`, with the graph's SQLite file beside it, and never replaces a config that is already there.

### Add a task, and list them

```sh
yak task new 'Add the sign-up page'
yak task list
```

### Browse it in a terminal

```sh
yak browse
yak browse T-1
```

Opens [@yaks/browse](https://github.com/yak-sh/yak/tree/main/packages/browse) on your graph in this terminal: your tasks at home, and with an id, that entity's page.

### Open it in a browser

```sh
yak serve
```

Serves the graph at `http://127.0.0.1:8787`, on this machine only, until you stop it: the same app at `/` to read and edit it, `/mcp` for agents and `/query` for programs.

### Bring your agents

```sh
yak hooks install
```

Each Claude Code session becomes a session entity in the graph. Any MCP client can call the graph's tools at `http://127.0.0.1:8787/mcp`.

### Reach yaks.app

```sh
yak auth yaks.app
```

Prints an address to open in a browser. Sign in there with your email, then paste back the address the browser lands on, and the same `yak` calls your yaks.app account.

### Connect Claude or ChatGPT

Add yaks.app to your assistant as a connector at `https://yaks.app/mcp`, and sign in with your email. [Its setup page](https://yaks.app/agent) has the steps for each assistant, written so the assistant can follow them.

### Put an app online

```sh
yak app_new --slug notes --title Notes
yak app_files --app notes --path index.html --content @index.html
yak app_deploy --app notes
```

With an `index.html` in this folder, these make the app, write that file as its page, and put it online at `yourname.yaks.app/notes`. Or ask Claude or ChatGPT for the app you want, and it calls the same tools.

## Use the packages on their own

yak is built from TypeScript packages on [JSR](https://jsr.io/@yaks). Many build on others, and each README says what it exports, how to set it up and where it stops.

| The graph | |
| --- | --- |
| [graph](https://github.com/yak-sh/yak/tree/main/packages/graph) | Entities, components and `apply()`, which checks a batch and commits it through a storage adapter. |
| [vocab](https://github.com/yak-sh/yak/tree/main/packages/vocab) | Components and their properties, declared as JSON Schema and read at runtime. |
| [query](https://github.com/yak-sh/yak/tree/main/packages/query) | Query strings such as `.task.status=open`, parsed into a syntax tree. |
| [id](https://github.com/yak-sh/yak/tree/main/packages/id) | Entity ids, and the short numbers people type, such as T-2. |
| [edge](https://github.com/yak-sh/yak/tree/main/packages/edge) | Links between entities, stored as entities, and walks across them. |
| [doc](https://github.com/yak-sh/yak/tree/main/packages/doc) | `doc{title, body}`, the text a task, a letter and a recipe share. |

| Storage | |
| --- | --- |
| [sqlite](https://github.com/yak-sh/yak/tree/main/packages/sqlite) | Storage in SQLite, with the database driver supplied by the caller. |
| [ram](https://github.com/yak-sh/yak/tree/main/packages/ram) | Storage in memory, for browsers and tests. The graph in this tab uses it. |
| [d1](https://github.com/yak-sh/yak/tree/main/packages/d1) | Storage in Cloudflare D1, each transaction sent as one batch. |
| [durable-object](https://github.com/yak-sh/yak/tree/main/packages/durable-object) | Storage in a Cloudflare Durable Object's SQLite. |
| [journal](https://github.com/yak-sh/yak/tree/main/packages/journal) | Every committed transaction, for history, undo and a change feed. |
| [fts](https://github.com/yak-sh/yak/tree/main/packages/fts) | Full-text search with SQLite FTS5. |

| Ways in | |
| --- | --- |
| [cli](https://github.com/yak-sh/yak/tree/main/packages/cli) | The `yak` command, whose subcommands are a graph's tools. |
| [api](https://github.com/yak-sh/yak/tree/main/packages/api) | HTTP: `/apply`, `/query`, and `/ws` subscriptions that push changed results. |
| [mcp](https://github.com/yak-sh/yak/tree/main/packages/mcp) | The graph's tools for agents, at `/mcp` or over stdio. |
| [client](https://github.com/yak-sh/yak/tree/main/packages/client) | A graph in the browser, connected to its server, with queries that update. |
| [sync](https://github.com/yak-sh/yak/tree/main/packages/sync) | Send local changes to a server, and reconcile or revert optimistic writes. |
| [workerd](https://github.com/yak-sh/yak/tree/main/packages/workerd) | The same HTTP handler as a Cloudflare Worker. |

| Agents and work | |
| --- | --- |
| [task](https://github.com/yak-sh/yak/tree/main/packages/task) | Tasks, with a status computed from their marks. |
| [session](https://github.com/yak-sh/yak/tree/main/packages/session) | Agent transcripts as entities, and claims on what a session works on. |
| [tools](https://github.com/yak-sh/yak/tree/main/packages/tools) | One registry of tools; each call and its result are stored in the graph. |
| [effects](https://github.com/yak-sh/yak/tree/main/packages/effects) | Code that runs after a commit, with retries and backoff. |
| [harness](https://github.com/yak-sh/yak/tree/main/packages/harness) | A local agent: model calls, shell and graph tools, and a terminal interface. |

### The same graph in your own code

This example keeps a document in memory and reads it back with a query. `@yaks/sqlite` keeps the same data in a file.

```sh
deno add jsr:@yaks/doc jsr:@yaks/graph jsr:@yaks/ram jsr:@yaks/vocab
```

```ts main.ts
import { docDoc } from '@yaks/doc'
import { graph } from '@yaks/graph'
import { ram } from '@yaks/ram'
import { loadVocab } from '@yaks/vocab'

let vocab = loadVocab([docDoc])
let g = graph({ storage: ram(vocab), vocab })
await g.apply([{
  entity: { eid: crypto.randomUUID() },
  doc: { title: 'Getting started', body: 'A document stored as components.' },
}])
console.log(await g.read('.doc.title="Getting started"'))
```

Run it with `deno run main.ts`. In a Node project, add the packages with `npx jsr add`.

## yak.sh

The yak command line and the @yaks packages.
- runs on: [Deno](https://deno.com)
- stored in: `~/.yak/yak.db`
- license: Apache-2.0
- source: [github.com/yak-sh/yak](https://github.com/yak-sh/yak)
- packages: [jsr.io/@yaks](https://jsr.io/@yaks)
- for agents: [llms.txt](llms.txt), [setup.md](setup.md) and [this page as Markdown](index.md)

