From 656c78027052990ca5662ddd9c00f55d36d301ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Mon, 1 Jun 2026 23:53:12 +0000 Subject: [PATCH] feat: add `ocas prompt usage` and `ocas prompt setup` commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `ocas prompt usage` — outputs skill body (SKILL.md content without frontmatter) - `ocas prompt setup` — outputs agent installation instructions Prompt content is bundled with the CLI and versioned with it. --- packages/cli/src/index.ts | 25 ++++ packages/cli/src/prompts/setup.md | 48 ++++++++ packages/cli/src/prompts/usage.md | 197 ++++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 packages/cli/src/prompts/setup.md create mode 100644 packages/cli/src/prompts/usage.md diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 1409f60..713d2fc 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1241,6 +1241,31 @@ switch (cmd) { await cmdGc(rest); break; + case "prompt": { + const [sub] = rest; + switch (sub) { + case "usage": { + const content = readFileSync( + join(import.meta.dir, "prompts", "usage.md"), + "utf-8", + ); + process.stdout.write(content); + break; + } + case "setup": { + const content = readFileSync( + join(import.meta.dir, "prompts", "setup.md"), + "utf-8", + ); + process.stdout.write(content); + break; + } + default: + die(`Unknown prompt subcommand: ${sub ?? "(none)"}. Available: usage, setup`); + } + break; + } + default: die(`Unknown command: ${cmd}`); } diff --git a/packages/cli/src/prompts/setup.md b/packages/cli/src/prompts/setup.md new file mode 100644 index 0000000..768cdd6 --- /dev/null +++ b/packages/cli/src/prompts/setup.md @@ -0,0 +1,48 @@ +# OCAS Skill Setup + +You are being asked to install or update the OCAS (Object Content Addressable Store) skill +so that you know how to use the `ocas` CLI. + +## Steps + +1. **Check if OCAS CLI is installed:** + ```bash + ocas --help + ``` + If not installed: `bun add -g @ocas/cli` + +2. **Get the usage skill content:** + ```bash + ocas prompt usage + ``` + +3. **Create a SKILL.md file** in your skill directory (e.g. `~/.hermes/skills/ocas/SKILL.md`). + The output of `ocas prompt usage` is the skill body WITHOUT frontmatter. + You must prepend the following YAML frontmatter: + + ```yaml + --- + name: ocas + description: "Use when storing, retrieving, or managing typed JSON data with OCAS (Object Content Addressable Store). Covers CLI usage, variable management, templates, rendering, and pipe composition." + version: + author: OCAS + license: MIT + metadata: + hermes: + tags: [cas, storage, cli, json, schema, content-addressing] + --- + ``` + + Replace `` with the installed CLI version (from `ocas prompt usage` header or `ocas --help`). + +4. **If updating an existing skill**, compare the `version` in your current SKILL.md + frontmatter with the installed CLI version. If the CLI is newer, replace the file. + +5. **Verify** the skill is loadable by your agent framework. + +## Notes + +- The skill content is bundled with the CLI and versioned with it — always use + `ocas prompt usage` to get the content matching your installed version. +- Do NOT hand-edit the skill body. If the CLI is updated, re-run `ocas prompt setup` + and follow the steps again. diff --git a/packages/cli/src/prompts/usage.md b/packages/cli/src/prompts/usage.md new file mode 100644 index 0000000..eb24037 --- /dev/null +++ b/packages/cli/src/prompts/usage.md @@ -0,0 +1,197 @@ +# OCAS — Object Content Addressable Store + +## Overview + +OCAS is a self-describing content-addressable store for typed JSON data. Every node has a `type` field (hash of a JSON Schema) and a `payload`. Hashes are 13-character Crockford Base32 strings (XXH64 over deterministic CBOR). + +All commands output `{ type, value }` JSON envelopes, making them composable via pipes. + +**Install:** `bun add -g @ocas/cli` + +**Packages:** `@ocas/core` (engine) · `@ocas/fs` (filesystem store) · `@ocas/cli` (CLI) + +## When to Use + +- Storing structured, schema-validated JSON data with content addressing +- Building knowledge graphs or DAGs with typed nodes and `cas_ref` edges +- Agent memory, config versioning, or any use case needing immutable data + mutable pointers +- Don't use for: binary blobs, large files, or high-throughput streaming + +## Quick Start + +```bash +# Register a schema (from stdin) +echo '{ + "type": "object", + "properties": { "title": { "type": "string" }, "done": { "type": "boolean" } }, + "required": ["title", "done"], + "additionalProperties": false +}' | ocas put @ocas/schema -p +# → { "type": "...", "value": "" } + +# Name it +ocas var set @todo/schema + +# Store data +echo '{ "title": "Buy milk", "done": false }' | ocas put @todo/schema -p + +# Retrieve + verify +ocas get +ocas verify +``` + +## Core Concepts + +### Hashes +13-char uppercase Crockford Base32 (e.g. `9S7JEYS3FKSDH`). Deterministic: same content → same hash. + +### Envelope Format +Every command outputs `{ type, value }`. `type` is the hash of the result schema. Pipe any envelope into `render -p` to render it human-readable. + +### Variables +Mutable pointers to immutable data (like git branches → commits). All names must follow `@scope/name` format: +- `@myapp/config` ✅ +- `@ocas/schema` ✅ (builtin, read-only) +- `config` ❌ (no scope) + +### Templates +LiquidJS templates bound to a schema. `render` uses the template for the node's type, falling back to YAML. + +## CLI Reference + +### Store & Retrieve + +```bash +ocas put # store node → hash +ocas put -p # read payload from stdin +ocas get # retrieve node +ocas has # check existence +ocas hash # compute hash without storing +ocas verify # integrity + schema validation +``` + +### Graph Traversal + +```bash +ocas refs # direct cas_ref edges +ocas walk # recursive DAG traversal +ocas walk --format tree # tree view +``` + +### Listing & Querying + +```bash +ocas list --type # list nodes by type +ocas list-schema # all schemas +ocas list-meta # meta-schema hashes +``` + +Sorting and pagination: + +```bash +ocas list --type @todo/schema --sort updated --desc --limit 20 +ocas list --type @todo/schema --offset 20 --limit 20 # page 2 +``` + +### Variables + +```bash +ocas var set @myapp/config # bind name → hash +ocas var set @myapp/config --tag env:prod --tag pinned +ocas var get @myapp/config # look up +ocas var delete @myapp/config # remove +ocas var list [prefix] # list (prefix filter) +ocas var list @myapp/ --tag env:prod # filter by scope + tag +ocas var history @myapp/config # last 10 values (LRU) +ocas var tag @myapp/config --schema status:active # add tag +ocas var tag @myapp/config --schema :status # remove tag +``` + +**Naming rules:** +- Format: `@scope/name` — `@[a-zA-Z][a-zA-Z0-9]*/segments` +- `@ocas/*` reserved for builtins +- Any command accepting a hash also accepts a variable name + +### Templates & Rendering + +```bash +ocas template set --inline "{{ payload.title }}" +ocas template get +ocas template list +ocas template delete +ocas render # render with template (or YAML fallback) +ocas render --pipe/-p # render from piped envelope +ocas get -r # inline render shorthand +``` + +Render options: `--resolution N` (max depth), `--decay N` (depth decay), `--epsilon N` (cutoff). + +### Garbage Collection + +```bash +ocas gc # collect unreachable nodes +ocas gc | ocas render -p # human-readable stats +``` + +### Global Flags + +| Flag | Description | +|------|-------------| +| `--home ` | Store directory (default: `$OCAS_HOME` or `~/.ocas`) | +| `--var-db ` | Variable database path | +| `--json` | Compact JSON output | +| `-p`, `--pipe` | Read from stdin | +| `-r`, `--render` | Render output inline | +| `--sort created\|updated` | Sort key (default: `created`) | +| `--limit ` | Max results (default: 100) | +| `--offset ` | Skip first N (default: 0) | +| `--desc` | Sort descending | + +## Pipe Composition Patterns + +```bash +# Store + render in one go +echo '{"title":"test","done":false}' | ocas put @todo/schema -p | ocas render -p + +# Or use -r shorthand +ocas get -r + +# List schemas, extract hashes with jq +ocas list --type @ocas/schema | jq -r '.value[].hash' + +# Render GC stats +ocas gc | ocas render -p +``` + +## Library Usage + +```typescript +import { bootstrap, createMemoryStore, putSchema } from "@ocas/core"; + +const store = createMemoryStore(); +await bootstrap(store); + +const typeHash = await putSchema(store, { + type: "object", + properties: { message: { type: "string" } }, + required: ["message"], + additionalProperties: false, +}); + +const hash = await store.put(typeHash, { message: "hello" }); +``` + +For filesystem persistence: + +```typescript +import { openStoreAndVarStore } from "@ocas/fs"; +const { store, varStore } = await openStoreAndVarStore("/path/to/store"); +``` + +## Common Pitfalls + +1. **Variable names without `@scope/`** — all names must be `@scope/name` format. `config` alone will be rejected. +2. **Writing to `@ocas/*` namespace** — reserved for builtins, CLI will reject. +3. **Forgetting `-p` for stdin** — `ocas put ` expects a file path; use `-p` to read from stdin. +4. **Expecting `list` to return hashes** — `list` commands return `ListEntry[]` with `{ hash, created, updated }`, not bare hashes. +5. **`workspace:*` in published packages** — only on `main` branch; release branches must have fixed versions. -- 2.43.0