Skip to main content
Glama
README.md
# Strata

Strata is a knowledge graph for a personal archive and the website published from it. It stores everything in one libSQL (Turso) database:

- **Archive entities**: works, projects, talks, events, people, places, themes, notes, with a markdown body and frontmatter.
- **Relations** between entities and source documents (`derived_from`, `shown_at`, `involved`, ...).
- **Source documents**: raw imported text, chunked for search.
- **Notes**: private captures, kept as entities of type `note` and served as a memory stream.
- **Publish projections**: the block or markdown content a site renders, versioned by revision.
- **Status feed**: dated entries (Reading, Travelling, Listening, ...) plus optional note pages.
- **Media**: images copied to Vercel Blob with responsive variants and rights metadata.

It ships as a CLI (`strata`), an MCP server (`strata-mcp`) and a TypeScript library. The site that renders the content is yours to write; Strata is the data layer behind it.

## Install

```sh
npm install -g @marcuswendt/strata
# or per project
npm install @marcuswendt/strata
```

Requires Node 22.12 or later. Image variant generation uses the optional dependency `sharp`.

## Database

Strata talks to libSQL over HTTP using `@libsql/client/web`, so the same code runs in serverless functions. That client cannot open `file:` URLs. For local work run a libSQL server:

```sh
sqld --db-path ./strata.sqld --http-listen-addr 127.0.0.1:8080
# or
turso dev --db-file ./strata.db --port 8080
```

and set `STRATA_DATABASE_URL=http://127.0.0.1:8080`. For Turso, use the `libsql://` URL and an auth token. The schema is applied automatically on first use.

## Configuration

Settings are read from, in order of precedence:

1. the process environment
2. the file given with `--env-file <path>` (both binaries accept it)
3. `.env.local` in the current working directory
4. `.env` in the current working directory

A value set earlier is never overridden by a later source.

| Variable | Purpose |
| --- | --- |
| `STRATA_DATABASE_URL` | libSQL URL (required). `TURSO_URL` is accepted as a fallback. |
| `STRATA_AUTH_TOKEN` | libSQL auth token. `TURSO_AUTH_TOKEN` is accepted as a fallback. |
| `BLOB_READ_WRITE_TOKEN` | Vercel Blob token, needed for `media sync`, `media ingest`, `media variants`. |
| `STRATA_SITE_NAME` | Name used in MCP tool descriptions. Neutral wording when unset. |
| `STRATA_SITE_URL` | Public site URL used for links in MCP results. Without it links are `strata:<ref>`. |
| `STRATA_REVALIDATE_URL` | Base URL for cache purges after writes. Defaults to `STRATA_SITE_URL`. |
| `STRATA_REVALIDATE_TOKEN` | Token sent as `x-prerender-revalidate` (Vercel ISR bypass token). `VERCEL_ISR_BYPASS_TOKEN` is accepted too. |
| `STRATA_PAGE_PATHS` | JSON map of page slug to route, for slugs that do not render at `/<slug>`, e.g. `{"press-kit":"/press_kit"}`. |
| `STRATA_REVALIDATE_CORE_PATHS` | Comma list purged by `strata revalidate --core`. Default `/`. |
| `STRATA_FRIENDS_PATHS` | Comma list purged after `strata friends` writes. Default `/about`. |
| `STRATA_NAV_SLUGS` | Comma list of page slugs linked from site navigation, so `surfaces orphans` skips them. |

Cache purging is optional. Without a revalidate URL and token, writes skip it silently.

## CLI

Every command takes `--json` for machine-readable output. `strata <command> --help` lists the options.

```sh
strata status                          # database URL and table counts
strata capture "an idea worth keeping"  # private note
strata search "glacier"                # notes, source chunks and entities
strata search "glacier" --scope public # public entities only
strata context "glacier" --purpose talk_brief
strata get work:glacier-light --body --relations
strata list work
```

| Group | Commands |
| --- | --- |
| Query | `status`, `search`, `get`, `context`, `list`, `diff` |
| Notes | `capture`, `memory context` |
| Sources | `source import`, `source search` |
| Archive | `archive list`, `new`, `show`, `link`, `relate`, `promote`, `delete` |
| Publishing | `publish`, `published list`, `page blocks`, `page pull`, `page push`, `page replace` |
| Status feed | `feed add`, `feed list`, `feed remove`, `feed note` |
| People | `friends list`, `friends add`, `friends remove` |
| Media | `media sync`, `media status`, `media variants`, `media repair`, `media ingest`, `media originals` |
| Health | `doctor`, `surfaces orphans` |
| Other | `assets list`, `assets effective`, `revalidate` |

In search and context results, private notes appear once, in the memory stream. They are not repeated among archive entities unless you ask for `--type note`.

## MCP

`strata-mcp` is an MCP server on stdio (newline-delimited JSON-RPC). Add it to a client such as Claude Code or Claude Desktop:

```json
{
  "mcpServers": {
    "strata": {
      "command": "npx",
      "args": ["-y", "-p", "@marcuswendt/strata", "strata-mcp", "--env-file", "/path/to/strata.env"]
    }
  }
}
```

Tools: `search`, `fetch`, `strata_search`, `strata_get`, `strata_context`, `strata_list`, `status_list`, `strata_status`, `strata_page_blocks`, `strata_diff`, `strata_page_replace`, `strata_doctor`, `strata_surfaces_orphans`, `strata_media_originals`. Pass `--public` to expose only `search` and `fetch`, restricted to public content.

To serve MCP over HTTP from your own app, use the tool layer directly:

```ts
import { buildStrataMcpTools, callStrataMcpTool } from "@marcuswendt/strata/mcp";
```

## Library

```ts
import {
  createStrataClient,
  resolveStrataDatabaseConfig,
  applyStrataSchema,
  captureStrataMemory,
  strataSearch,
  getPublishedContent,
} from "@marcuswendt/strata";

const config = resolveStrataDatabaseConfig(); // or { url, authToken }
const db = createStrataClient(config);
await applyStrataSchema(db);

await captureStrataMemory(db, { title: "First note", body: "..." });
const results = await strataSearch(db, { query: "note", scope: "private" });

db.close();
```

All repository functions take the libSQL client as their first argument. Types are included.

## Development

```sh
npm install
npm run build     # tsc to dist/
npm run assets    # regenerate the bundled policy assets after editing assets/
```

## License

MIT, see [LICENSE](LICENSE).

Maintenance

ActivityMaintained
ResponsivenessNo issues