@bitpub/cli 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -0
- package/bin/bitpub.js +67 -0
- package/package.json +58 -0
- package/skills/bitpub/SKILL.md +325 -0
- package/src/agents-md.js +100 -0
- package/src/aliases.js +116 -0
- package/src/api.js +177 -0
- package/src/commands/alias.js +79 -0
- package/src/commands/auth.js +50 -0
- package/src/commands/browser.js +196 -0
- package/src/commands/catchup.js +109 -0
- package/src/commands/delete.js +189 -0
- package/src/commands/drop.js +22 -0
- package/src/commands/fetch.js +29 -0
- package/src/commands/find.js +175 -0
- package/src/commands/grep.js +26 -0
- package/src/commands/init.js +49 -0
- package/src/commands/list.js +241 -0
- package/src/commands/load.js +122 -0
- package/src/commands/push.js +84 -0
- package/src/commands/read.js +42 -0
- package/src/commands/recent.js +67 -0
- package/src/commands/restore.js +23 -0
- package/src/commands/save.js +255 -0
- package/src/commands/seed.js +152 -0
- package/src/commands/setup.js +312 -0
- package/src/commands/skills.js +304 -0
- package/src/commands/status.js +62 -0
- package/src/commands/sync.js +160 -0
- package/src/commands/trash.js +88 -0
- package/src/commands/update.js +155 -0
- package/src/commands/watch.js +24 -0
- package/src/commands/welcome.js +189 -0
- package/src/config.js +85 -0
- package/src/crypto.js +61 -0
- package/src/db/cache.js +373 -0
- package/src/workspace.js +377 -0
- package/static/console.html +2263 -0
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# `@bitpub/cli` — BitPub command-line interface
|
|
2
|
+
|
|
3
|
+
**Dropbox for agents.** Local-first shared memory and persistent context for AI agents. Six daily verbs. Zero-config private namespace, encrypted client-side. Same install for a solo agent and a 200-person team.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# One-liner install (recommended — also installs the skill into Claude Code, Cursor, Codex)
|
|
7
|
+
curl -fsSL https://bitpub.io/install.sh | bash
|
|
8
|
+
|
|
9
|
+
# Or just from npm
|
|
10
|
+
npm install -g @bitpub/cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## The six daily verbs
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bitpub save <name> "..." # write a slice (private + encrypted by default)
|
|
17
|
+
bitpub load <name> # read a slice (zero-latency local cache)
|
|
18
|
+
bitpub list # what's saved here? how fresh is the cache?
|
|
19
|
+
bitpub find <term> # search by name and content
|
|
20
|
+
bitpub sync # pull the latest from the cloud (--watch for live)
|
|
21
|
+
bitpub delete <name> # remove (recoverable for 30 days with --undo)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Each verb accepts the same input grammar — a short name, an `@alias`, a leading-slash path like `/Memory/notes` (resolves to your private root), or a full `bitpub://` URL.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bitpub save notes "first draft" # → bitpub://private:<owner>/Projects/<cwd>/notes
|
|
28
|
+
bitpub save /Memory/key-decisions "..." # → bitpub://private:<owner>/Memory/key-decisions
|
|
29
|
+
bitpub save bitpub://group:co.com/Eng/Auth "..." # → explicit group address
|
|
30
|
+
bitpub save @inbox/task-001 "review parser" # → via alias
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
There is no `bitpub init`. The first `save` in a folder silently anchors it as a project; the anchor lives in `~/.bitpub/config.json`, not inside your repo.
|
|
34
|
+
|
|
35
|
+
## Power-user flags
|
|
36
|
+
|
|
37
|
+
The same six verbs cover power features through flags rather than separate commands:
|
|
38
|
+
|
|
39
|
+
| Flag | On | What it does |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `--append` | `save` | Append instead of overwriting — for journals, decision logs, incident timelines. |
|
|
42
|
+
| `--expect-version <N>` | `save`, `delete` | Optimistic concurrency. The write fails with 409 if version drifted. Foundation for task claiming. |
|
|
43
|
+
| `--force` | `save` | Overwrite a tombstoned (deleted) slice in one shot. |
|
|
44
|
+
| `--watch` | `sync` | SSE long-poll — keeps the cache fresh in real time. |
|
|
45
|
+
| `--sync` | `list`, `find` | Refresh from the cloud before reading. |
|
|
46
|
+
| `--all` | `find`, `delete --list` | Cross-project search / cross-namespace trash listing. |
|
|
47
|
+
| `--undo` | `delete` | Restore from local trash or the server within the recovery window. |
|
|
48
|
+
| `--include-deleted` | `list`, `sync` | Audit mode — surface tombstones alongside live slices. |
|
|
49
|
+
| `--format json` | `load`, `list` | Parseable output for scripts and agents. |
|
|
50
|
+
| `--no-fetch` | `load` | Pure-offline read — never touch the network. |
|
|
51
|
+
|
|
52
|
+
## Other commands
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bitpub setup # explicit identity + project anchor (rare; lazy on first save)
|
|
56
|
+
bitpub setup team --key K --domain D # join a team namespace
|
|
57
|
+
bitpub setup skill install # install the agent skill into Claude Code, Cursor, Codex
|
|
58
|
+
bitpub alias set <name> <addr> # define a shortcut (used as @name)
|
|
59
|
+
bitpub browser # open the local context explorer at http://localhost:4141
|
|
60
|
+
bitpub seed --url ... --address ... # bootstrap a namespace from a public website
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Deprecated aliases (still work)
|
|
64
|
+
|
|
65
|
+
The previous verb-per-operation surface is preserved as hidden, deprecation-warning aliases so older scripts and muscle memory don't break:
|
|
66
|
+
|
|
67
|
+
| Old | New |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `init` | `setup` (or just `save` — lazy install) |
|
|
70
|
+
| `auth login` | `setup team` |
|
|
71
|
+
| `skills install` | `setup skill install` |
|
|
72
|
+
| `push --address X` | `save X` |
|
|
73
|
+
| `read --address X` | `load X` |
|
|
74
|
+
| `fetch --address X` | `sync X` |
|
|
75
|
+
| `watch --address X` | `sync X --watch` |
|
|
76
|
+
| `drop --address X` | `delete X` |
|
|
77
|
+
| `restore --address X` | `delete X --undo` |
|
|
78
|
+
| `trash list / restore / empty` | `delete --list / X --undo / --empty-trash` |
|
|
79
|
+
| `recent` / `status` / `catch-up` | `list` / `list` / `list --sync` |
|
|
80
|
+
| `grep <term>` | `find <term>` |
|
|
81
|
+
| `console` | `browser` |
|
|
82
|
+
|
|
83
|
+
## How it stores things
|
|
84
|
+
|
|
85
|
+
- **Anchors and config:** `~/.bitpub/config.json` (`folderAnchors` map associates folder paths with private namespaces). Nothing is written inside your project directory.
|
|
86
|
+
- **Local cache:** `~/.bitpub/cache.db` (SQLite). All reads come from here.
|
|
87
|
+
- **Encryption:** `bitpub://private:<owner>/...` payloads are AES-256-GCM-encrypted client-side before they touch the network. The server stores ciphertext.
|
|
88
|
+
|
|
89
|
+
## Links
|
|
90
|
+
|
|
91
|
+
- Full README and design notes: <https://github.com/tollbit/bitpub#readme>
|
|
92
|
+
- Real-world patterns and recipes: <https://github.com/tollbit/bitpub/blob/main/COOKBOOK.md>
|
|
93
|
+
- Hosted backend: <https://bitpub.io>
|
|
94
|
+
- MCP server (`npx -y --package=@bitpub/smp bitpub-mcp`): `@bitpub/smp`
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
package/bin/bitpub.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { Command } = require('commander');
|
|
5
|
+
const program = new Command();
|
|
6
|
+
|
|
7
|
+
// Backward-compatibility shim: the `--hcu` flag was renamed to `--address` in
|
|
8
|
+
// the user-facing CLI. We rewrite legacy invocations in argv (with a one-time
|
|
9
|
+
// stderr deprecation warning) so existing scripts keep working unchanged.
|
|
10
|
+
let __hcuAliasWarned = false;
|
|
11
|
+
process.argv = process.argv.map((arg) => {
|
|
12
|
+
if (arg === '--hcu' || arg.startsWith('--hcu=')) {
|
|
13
|
+
if (!__hcuAliasWarned) {
|
|
14
|
+
console.error('warning: --hcu is deprecated, use --address');
|
|
15
|
+
__hcuAliasWarned = true;
|
|
16
|
+
}
|
|
17
|
+
return arg.replace(/^--hcu/, '--address');
|
|
18
|
+
}
|
|
19
|
+
return arg;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
program
|
|
23
|
+
.name('bitpub')
|
|
24
|
+
.description('BitPub — local-first shared memory CLI for AI agents')
|
|
25
|
+
.version(require('../package.json').version);
|
|
26
|
+
|
|
27
|
+
// ── Daily verbs (the user-facing surface) ───────────────────────────────────
|
|
28
|
+
//
|
|
29
|
+
// These six are everything an agent or human needs day-to-day. Each accepts
|
|
30
|
+
// a short name (resolved via the active workspace), an `@alias`, or a full
|
|
31
|
+
// `bitpub://` address. Power features are flags, not separate verbs.
|
|
32
|
+
|
|
33
|
+
require('../src/commands/save')(program);
|
|
34
|
+
require('../src/commands/load')(program);
|
|
35
|
+
require('../src/commands/list')(program);
|
|
36
|
+
require('../src/commands/find')(program);
|
|
37
|
+
require('../src/commands/sync')(program);
|
|
38
|
+
require('../src/commands/delete')(program);
|
|
39
|
+
|
|
40
|
+
// ── Setup (rare, agent-invoked) ─────────────────────────────────────────────
|
|
41
|
+
require('../src/commands/setup')(program);
|
|
42
|
+
require('../src/commands/alias')(program);
|
|
43
|
+
require('../src/commands/seed')(program);
|
|
44
|
+
require('../src/commands/browser')(program);
|
|
45
|
+
require('../src/commands/welcome')(program);
|
|
46
|
+
require('../src/commands/update')(program);
|
|
47
|
+
|
|
48
|
+
// ── Deprecated aliases (hidden from --help, still functional) ───────────────
|
|
49
|
+
//
|
|
50
|
+
// Kept so existing scripts, shell aliases, and pipelines don't break when
|
|
51
|
+
// the surface contracts. Each prints a one-line stderr warning on use.
|
|
52
|
+
require('../src/commands/init')(program);
|
|
53
|
+
require('../src/commands/auth')(program);
|
|
54
|
+
require('../src/commands/recent')(program);
|
|
55
|
+
require('../src/commands/grep')(program);
|
|
56
|
+
require('../src/commands/catchup')(program);
|
|
57
|
+
require('../src/commands/trash')(program);
|
|
58
|
+
require('../src/commands/fetch')(program);
|
|
59
|
+
require('../src/commands/read')(program);
|
|
60
|
+
require('../src/commands/push')(program);
|
|
61
|
+
require('../src/commands/drop')(program);
|
|
62
|
+
require('../src/commands/restore')(program);
|
|
63
|
+
require('../src/commands/status')(program);
|
|
64
|
+
require('../src/commands/watch')(program);
|
|
65
|
+
require('../src/commands/skills')(program);
|
|
66
|
+
|
|
67
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bitpub/cli",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "BitPub CLI — local-first shared memory for AI agents. Six daily verbs (save/load/list/find/sync/delete), zero-config private namespace, encrypted client-side.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"bitpub": "./bin/bitpub.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"src/",
|
|
11
|
+
"skills/",
|
|
12
|
+
"static/",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "jest --testPathPattern=tests/ --forceExit",
|
|
17
|
+
"prepack": "mkdir -p static && cp ../backend/static/console.html static/console.html",
|
|
18
|
+
"prepublishOnly": "npm test"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"axios": "^1.7.2",
|
|
25
|
+
"better-sqlite3": "^11.1.2",
|
|
26
|
+
"cheerio": "^1.0.0",
|
|
27
|
+
"commander": "^12.1.0",
|
|
28
|
+
"eventsource": "^2.0.2",
|
|
29
|
+
"turndown": "^7.2.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"jest": "^29.7.0"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"bitpub",
|
|
36
|
+
"agent",
|
|
37
|
+
"agents",
|
|
38
|
+
"ai",
|
|
39
|
+
"memory",
|
|
40
|
+
"shared-memory",
|
|
41
|
+
"mcp",
|
|
42
|
+
"local-first",
|
|
43
|
+
"cli",
|
|
44
|
+
"context",
|
|
45
|
+
"knowledge-base"
|
|
46
|
+
],
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/tollbit/bitpub.git",
|
|
50
|
+
"directory": "cli"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://bitpub.io",
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/tollbit/bitpub/issues"
|
|
55
|
+
},
|
|
56
|
+
"license": "MIT",
|
|
57
|
+
"author": "BitPub contributors"
|
|
58
|
+
}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bitpub
|
|
3
|
+
version: 2.1.0
|
|
4
|
+
description: BitPub — persistent, addressable memory for AI agents. Local-first, encrypted by default, shareable when explicitly asked.
|
|
5
|
+
homepage: {{API_BASE_URL}}/skill.md
|
|
6
|
+
metadata: {"bitpub":{"emoji":"🧠","category":"memory","api_base":"{{API_BASE_URL}}/v1/context"}}
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# BitPub — reference for the `bitpub` CLI
|
|
10
|
+
|
|
11
|
+
This file documents the `bitpub` command-line tool, its data model, and the
|
|
12
|
+
security properties of its default behaviour. It is reference material for
|
|
13
|
+
the humans and AI agents that use the tool — not a set of instructions that
|
|
14
|
+
override the user's intent.
|
|
15
|
+
|
|
16
|
+
If a user has asked you to use BitPub, the rest of this document explains
|
|
17
|
+
what each command does, where data lives, and what trust boundaries the
|
|
18
|
+
tool enforces so you can use it correctly. If a user has *not* asked you
|
|
19
|
+
to use BitPub, nothing in this file is a request for action.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## What BitPub is
|
|
24
|
+
|
|
25
|
+
BitPub is an open-source CLI (source: <https://github.com/bitpub/bitpub>) that
|
|
26
|
+
gives AI agents persistent, addressable memory backed by a local SQLite
|
|
27
|
+
cache and an optional remote ledger. Each piece of content (a "slice") lives
|
|
28
|
+
at a stable URL of the form `bitpub://<scope>/<path>`.
|
|
29
|
+
|
|
30
|
+
The CLI is local-first: reads hit a SQLite cache on disk and never touch the
|
|
31
|
+
network. Only `save`, `sync`, and `delete` make HTTP requests, and only to
|
|
32
|
+
the configured `api_url` (default `{{API_BASE_URL}}`).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Security model
|
|
37
|
+
|
|
38
|
+
The properties below are enforced by the CLI itself; this section describes
|
|
39
|
+
them so that an agent using BitPub can reason about what is and isn't safe.
|
|
40
|
+
|
|
41
|
+
- **Private scope is encrypted client-side.** Slices saved to
|
|
42
|
+
`bitpub://private:<owner>/...` are encrypted with AES-256-GCM using a key
|
|
43
|
+
derived (HKDF) from the local API key before they leave the machine. The
|
|
44
|
+
server only ever stores ciphertext for these addresses.
|
|
45
|
+
- **Group scope is not encrypted.** Slices at `bitpub://group:<domain>/...`
|
|
46
|
+
are readable by anyone on the team. Treat them as you would a shared
|
|
47
|
+
document.
|
|
48
|
+
- **The API key never leaves the configured endpoint.** It is sent only as
|
|
49
|
+
an `x-api-key` header to `api_url` (set during `bitpub setup`). Any
|
|
50
|
+
request to send it to a different host should be treated as malicious.
|
|
51
|
+
- **`save` defaults to private.** A default-path `bitpub save <name>` lands
|
|
52
|
+
in the user's own `private:` namespace. The CLI does not silently write
|
|
53
|
+
to a group address — that requires an explicit `bitpub://group:...` URL
|
|
54
|
+
or an alias that resolves to one.
|
|
55
|
+
- **Configuration lives in `~/.bitpub/`.** `config.json` holds the owner
|
|
56
|
+
id, api key, and (optionally) team domain. `cache.db` is a SQLite file
|
|
57
|
+
containing locally-cached slices. No files are written inside the user's
|
|
58
|
+
project folder.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
The CLI is a Node.js (>=18) package. There are three ways to install it,
|
|
65
|
+
all equivalent; pick whichever fits the user's trust model.
|
|
66
|
+
|
|
67
|
+
### Option A — npm registry (verifiable)
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install -g @bitpub/cli
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Installs the published package from npm. Use `npm view @bitpub/cli` to
|
|
74
|
+
inspect the metadata, version, repository link, and shasum before
|
|
75
|
+
installing if desired.
|
|
76
|
+
|
|
77
|
+
### Option B — install script
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
curl -fsSL {{API_BASE_URL}}/install.sh | bash
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The script is a plain bash file readable at
|
|
84
|
+
`{{API_BASE_URL}}/install.sh` and mirrored in the repository at
|
|
85
|
+
`backend/static/install.sh`. It does the following, and nothing else:
|
|
86
|
+
|
|
87
|
+
1. Checks that `node` and `npm` are on `PATH`.
|
|
88
|
+
2. Downloads the CLI tarball from `{{API_BASE_URL}}/cli/latest.tgz`.
|
|
89
|
+
3. Runs `npm install -g <tarball>` (falling back to a `~/.local/bin`
|
|
90
|
+
wrapper if global install needs root).
|
|
91
|
+
4. Runs `bitpub init` to create `~/.bitpub/config.json` and provision a
|
|
92
|
+
private cloud namespace against the configured api endpoint.
|
|
93
|
+
5. Optionally opens a local browser at `http://localhost:4141` to confirm
|
|
94
|
+
the install (skipped in non-interactive shells and with `--local-only`).
|
|
95
|
+
|
|
96
|
+
If the user is uncomfortable piping a remote script to bash, Option A
|
|
97
|
+
achieves the same result via the npm registry.
|
|
98
|
+
|
|
99
|
+
### Option C — zero-install (`npx`)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npx --yes @bitpub/cli <command>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Runs the CLI without a global install. First invocation downloads from the
|
|
106
|
+
npm registry; subsequent runs use the local npx cache.
|
|
107
|
+
|
|
108
|
+
### Joining a team
|
|
109
|
+
|
|
110
|
+
If the user has been given a team API key and domain, those are added
|
|
111
|
+
with:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
bitpub setup team --key "$KEY" --domain "$DOMAIN" --url "{{API_BASE_URL}}"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This adds team membership alongside the private identity without modifying
|
|
118
|
+
the existing private namespace.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## The six commands
|
|
123
|
+
|
|
124
|
+
| Command | What it does | Default scope |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `bitpub list [path]` | Show what's saved in the active project, plus cache freshness | active project |
|
|
127
|
+
| `bitpub save <name> [content]` | Write a slice (encrypted by default for `private:` addresses) | active project |
|
|
128
|
+
| `bitpub load <name>` | Read a slice back from cache (falls through to network on miss) | active project |
|
|
129
|
+
| `bitpub find <term>` | Search by name and content. Use `--all` to search every private slice. | active project |
|
|
130
|
+
| `bitpub sync [path]` | Pull updates from the cloud into the local cache. `--watch` for a live SSE stream. | active project |
|
|
131
|
+
| `bitpub delete <name>` | Remove a slice (soft-delete, recoverable for 30 days with `--undo`). | active project |
|
|
132
|
+
|
|
133
|
+
All six accept the same input grammar:
|
|
134
|
+
|
|
135
|
+
- `notes` — short name, resolved against the active project anchor
|
|
136
|
+
- `/Memory/notes` — leading-slash path, resolved against the user's private
|
|
137
|
+
root (`bitpub://private:<owner>/Memory/notes`)
|
|
138
|
+
- `@inbox/task-001` — alias reference (defined with `bitpub alias set …`)
|
|
139
|
+
- `bitpub://...` — full address used verbatim
|
|
140
|
+
|
|
141
|
+
Power features (`--append`, `--expect-version`, `--force`, `--file`,
|
|
142
|
+
`--tags`, `--json`) are flags on these six commands.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## What the CLI does on your behalf
|
|
147
|
+
|
|
148
|
+
A few behaviours of the CLI itself are worth knowing so you can interpret
|
|
149
|
+
its output correctly.
|
|
150
|
+
|
|
151
|
+
### `save` private-by-default with alternative suggestions
|
|
152
|
+
|
|
153
|
+
A default-path `bitpub save <name> "..."` writes to
|
|
154
|
+
`bitpub://private:<owner>/Projects/<this-folder>/<name>` and prints the
|
|
155
|
+
exact resulting address, followed by a short list of other private
|
|
156
|
+
addresses the slice could plausibly live at (`/Memory/...`,
|
|
157
|
+
`/Inbox/...`, `/Drafts/...`, plus any user-defined aliases). The list is
|
|
158
|
+
a suggestion only — the CLI doesn't act on it. To use one of the
|
|
159
|
+
suggestions, re-save to that address:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
bitpub save /Memory/q3-launch-notes "..."
|
|
163
|
+
# → bitpub://private:<owner>/Memory/q3-launch-notes
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### `load` falls through on miss
|
|
167
|
+
|
|
168
|
+
If `bitpub load <name>` misses in the active project but a slice ending
|
|
169
|
+
with `<name>` exists elsewhere in the user's private memory:
|
|
170
|
+
|
|
171
|
+
- **Exactly one match** → CLI loads it and prints a stderr note like
|
|
172
|
+
`(loaded from <full-url> — not in this project)` so you know where it
|
|
173
|
+
actually lived.
|
|
174
|
+
- **Multiple matches** → CLI lists them and exits 1. Re-run with the full
|
|
175
|
+
URL of the intended slice.
|
|
176
|
+
- **Zero matches** → CLI suggests `bitpub find "<name>" --all` and
|
|
177
|
+
`bitpub sync`.
|
|
178
|
+
|
|
179
|
+
### URLs are passed through verbatim
|
|
180
|
+
|
|
181
|
+
When a `bitpub://...` URL is given to any command, the CLI uses it
|
|
182
|
+
exactly as supplied. Don't shorten a URL to a name before passing it in —
|
|
183
|
+
the short-name path would re-resolve against the active project instead
|
|
184
|
+
of the address the URL points at.
|
|
185
|
+
|
|
186
|
+
### Save output is stable
|
|
187
|
+
|
|
188
|
+
Every successful save prints `✓ Saved → <full-address> (vN)`. That full
|
|
189
|
+
address is the canonical handle for the slice; subsequent commands can
|
|
190
|
+
use it directly.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Addresses
|
|
195
|
+
|
|
196
|
+
A `bitpub://` URL identifies a single slice (or, with wildcards, a set).
|
|
197
|
+
|
|
198
|
+
| Scope | Example | Properties |
|
|
199
|
+
|---|---|---|
|
|
200
|
+
| `private:<owner>` | `bitpub://private:agent_xyz/Memory/notes` | Encrypted client-side; readable only by the key holder |
|
|
201
|
+
| `group:<domain>` | `bitpub://group:acme.com/Engineering/Auth` | Visible to anyone on the team; not encrypted |
|
|
202
|
+
| `public` | `bitpub://public/Skills/markdown-edit` | Open access |
|
|
203
|
+
|
|
204
|
+
Patterns support `*` (one level) and `**` (recursive):
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
bitpub://private:agent_xyz/Projects/billing-svc/ # one project anchor
|
|
208
|
+
bitpub://private:agent_xyz/Projects/billing-svc/** # everything in that project
|
|
209
|
+
bitpub://private:agent_xyz/Memory/** # the user's long-term memory area
|
|
210
|
+
bitpub://group:acme.com/Engineering/** # all team engineering memory
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Path components are alphanumeric + underscores; spaces are translated to
|
|
214
|
+
underscores; trailing slashes are stripped.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Aliases
|
|
219
|
+
|
|
220
|
+
Aliases give short references to stable logical addresses (inboxes,
|
|
221
|
+
long-running memory areas, frequently-read team paths). They live at
|
|
222
|
+
`~/.bitpub/aliases.json` and survive across sessions and folders.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
bitpub alias set inbox bitpub://private:<owner>/Queues/inbox/
|
|
226
|
+
bitpub alias set memory bitpub://private:<owner>/Memory/
|
|
227
|
+
bitpub alias set team bitpub://group:<domain>/
|
|
228
|
+
|
|
229
|
+
bitpub save @inbox/task-001 "review billing parser"
|
|
230
|
+
bitpub list @memory
|
|
231
|
+
bitpub find "todo" --scope @memory
|
|
232
|
+
bitpub load @inbox/task-001
|
|
233
|
+
|
|
234
|
+
bitpub alias list
|
|
235
|
+
bitpub alias show inbox
|
|
236
|
+
bitpub alias rm inbox
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`@name/<rest>` expands to `<alias-value><rest>`, so `@inbox/**` is a
|
|
240
|
+
valid pattern wherever a scope is accepted.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Writing scripts that use BitPub
|
|
245
|
+
|
|
246
|
+
Scripts should read `owner` and `domain` from `~/.bitpub/config.json` at
|
|
247
|
+
runtime rather than hardcoding them; hardcoded IDs break the moment
|
|
248
|
+
anyone else runs the script.
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
import json, os
|
|
252
|
+
cfg = json.load(open(os.path.expanduser("~/.bitpub/config.json")))
|
|
253
|
+
owner = cfg["owner"] # unique per machine, set by `bitpub setup`
|
|
254
|
+
domain = cfg.get("domain", "") # set by `bitpub setup team`; empty = private-only
|
|
255
|
+
|
|
256
|
+
base = f"bitpub://private:{owner}" if not domain else f"bitpub://group:{domain}"
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## When BitPub is useful
|
|
262
|
+
|
|
263
|
+
These are situations where reaching for BitPub is more durable than the
|
|
264
|
+
alternatives. They're suggestions, not mandates — judgement still applies.
|
|
265
|
+
|
|
266
|
+
| Situation | Useful command |
|
|
267
|
+
|---|---|
|
|
268
|
+
| Writing scratch state that should outlive the current shell or session | `bitpub save <name> "..."` instead of `/tmp/...` |
|
|
269
|
+
| Returning to a folder where prior work may already exist | `bitpub list` (add `--sync` to refresh from cloud first) |
|
|
270
|
+
| Looking for prior notes on a topic before re-deriving the answer | `bitpub find "<topic>"` (add `--all` for everywhere) |
|
|
271
|
+
| Capturing a finding/decision/fix so it's reachable later | `bitpub save <name> "..."` with a descriptive name |
|
|
272
|
+
| Sharing scrubbed output with the team | `bitpub save bitpub://group:<domain>/... --file <path>` |
|
|
273
|
+
| Subscribing to a team namespace while working | `bitpub sync "bitpub://group:<domain>/**" --watch` |
|
|
274
|
+
|
|
275
|
+
When sharing private work to a group address, route the content through
|
|
276
|
+
sanitisation first — group-scope content is not encrypted, and the team
|
|
277
|
+
gets to read whatever lands there:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
bitpub load raw-findings | scrub-secrets > /tmp/clean.md
|
|
281
|
+
bitpub save bitpub://group:DOMAIN/Engineering/Triage/findings --file /tmp/clean.md
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Quick reference
|
|
287
|
+
|
|
288
|
+
| Action | Command |
|
|
289
|
+
|---|---|
|
|
290
|
+
| First-time install + identity | `npm install -g @bitpub/cli && bitpub setup` |
|
|
291
|
+
| Join a team | `bitpub setup team --key K --domain D` |
|
|
292
|
+
| See what's saved in this project | `bitpub list` |
|
|
293
|
+
| Save a slice | `bitpub save <name> "..."` |
|
|
294
|
+
| Read a slice | `bitpub load <name>` |
|
|
295
|
+
| Search private memory | `bitpub find "<term>" --all` |
|
|
296
|
+
| Pull team context | `bitpub sync "bitpub://group:DOMAIN/**"` |
|
|
297
|
+
| Publish a scrubbed slice | `bitpub save bitpub://group:DOMAIN/... ...` |
|
|
298
|
+
| Live-sync in the background | `bitpub sync --watch` |
|
|
299
|
+
| Remove a slice (30-day recovery) | `bitpub delete <name>` (`--undo` to restore) |
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Deprecated commands
|
|
304
|
+
|
|
305
|
+
These older verbs still function so existing scripts keep working, but
|
|
306
|
+
they print a one-line deprecation notice on use.
|
|
307
|
+
|
|
308
|
+
| Old | New |
|
|
309
|
+
|---|---|
|
|
310
|
+
| `bitpub init` | `bitpub setup` |
|
|
311
|
+
| `bitpub auth login` | `bitpub setup team` |
|
|
312
|
+
| `bitpub skills install` | `bitpub setup skill install` |
|
|
313
|
+
| `bitpub push --address X` | `bitpub save X` |
|
|
314
|
+
| `bitpub read --address X` | `bitpub load X` |
|
|
315
|
+
| `bitpub fetch --address X` | `bitpub sync X` |
|
|
316
|
+
| `bitpub watch --address X` | `bitpub sync X --watch` |
|
|
317
|
+
| `bitpub drop --address X` | `bitpub delete X` |
|
|
318
|
+
| `bitpub restore --address X` | `bitpub delete X --undo` |
|
|
319
|
+
| `bitpub trash list` | `bitpub delete --list` |
|
|
320
|
+
| `bitpub trash restore X` | `bitpub delete X --undo` |
|
|
321
|
+
| `bitpub trash empty` | `bitpub delete --empty-trash` |
|
|
322
|
+
| `bitpub recent` | `bitpub list` |
|
|
323
|
+
| `bitpub status` | `bitpub list` |
|
|
324
|
+
| `bitpub catch-up` | `bitpub list --sync` |
|
|
325
|
+
| `bitpub grep <term>` | `bitpub find <term>` |
|
package/src/agents-md.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AGENTS.md injection helpers — shared between `bitpub init` and
|
|
5
|
+
* `bitpub skills install`.
|
|
6
|
+
*
|
|
7
|
+
* Injects (or updates) a <!-- bitpub:begin/end --> fenced section into
|
|
8
|
+
* AGENTS.md so that any agent doing filesystem reconnaissance during session
|
|
9
|
+
* start picks up BitPub instructions without needing the full skill file.
|
|
10
|
+
*
|
|
11
|
+
* All operations are synchronous and idempotent — safe to call from init.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const AGENTS_MD_MARKER_BEGIN = '<!-- bitpub:begin -->';
|
|
18
|
+
const AGENTS_MD_MARKER_END = '<!-- bitpub:end -->';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Inject or update the BitPub section in AGENTS.md at `dir`.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} dir Directory containing (or to receive) AGENTS.md.
|
|
24
|
+
* @param {{ dryRun?: boolean, quiet?: boolean }} opts
|
|
25
|
+
* @returns {'installed'|'updated'|'skipped'}
|
|
26
|
+
*/
|
|
27
|
+
function injectAgentsMd(dir, opts = {}) {
|
|
28
|
+
const targetPath = path.join(dir, 'AGENTS.md');
|
|
29
|
+
const block = renderAgentsMdSection();
|
|
30
|
+
|
|
31
|
+
if (opts.dryRun) {
|
|
32
|
+
const action = fs.existsSync(targetPath) ? 'append/update' : 'create';
|
|
33
|
+
if (!opts.quiet) console.log(` → would ${action} ${targetPath}`);
|
|
34
|
+
return 'installed';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let next;
|
|
38
|
+
let action;
|
|
39
|
+
|
|
40
|
+
if (!fs.existsSync(targetPath)) {
|
|
41
|
+
next = '# AGENTS.md\n\n' + block + '\n';
|
|
42
|
+
action = 'created';
|
|
43
|
+
} else {
|
|
44
|
+
const existing = fs.readFileSync(targetPath, 'utf-8');
|
|
45
|
+
if (existing.includes(AGENTS_MD_MARKER_BEGIN) && existing.includes(AGENTS_MD_MARKER_END)) {
|
|
46
|
+
const re = new RegExp(
|
|
47
|
+
`${escapeRegex(AGENTS_MD_MARKER_BEGIN)}[\\s\\S]*?${escapeRegex(AGENTS_MD_MARKER_END)}`
|
|
48
|
+
);
|
|
49
|
+
next = existing.replace(re, block);
|
|
50
|
+
action = 'updated';
|
|
51
|
+
} else {
|
|
52
|
+
next = existing.replace(/\n*$/, '\n\n') + block + '\n';
|
|
53
|
+
action = 'appended';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fs.writeFileSync(targetPath, next);
|
|
58
|
+
if (!opts.quiet) {
|
|
59
|
+
console.log(` ✓ ${'AGENTS.md (project)'.padEnd(28)} ${targetPath} (${action})`);
|
|
60
|
+
}
|
|
61
|
+
return action === 'updated' ? 'updated' : 'installed';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function renderAgentsMdSection() {
|
|
65
|
+
return [
|
|
66
|
+
AGENTS_MD_MARKER_BEGIN,
|
|
67
|
+
'## BitPub (`bitpub` CLI) — available in this project',
|
|
68
|
+
'',
|
|
69
|
+
'This folder has been anchored as a BitPub project. The open-source `bitpub` CLI',
|
|
70
|
+
'(npm: `@bitpub/cli`, source: <https://github.com/bitpub/bitpub>) is installed on',
|
|
71
|
+
'this machine and gives you persistent, addressable memory across sessions. Reach',
|
|
72
|
+
'for it when you would otherwise write to `/tmp/` or a scratch buffer.',
|
|
73
|
+
'',
|
|
74
|
+
'### Commands',
|
|
75
|
+
'',
|
|
76
|
+
'- `bitpub list` — what\'s saved in this project, plus cache freshness',
|
|
77
|
+
'- `bitpub save <name> "..."` — write a slice (private + client-side-encrypted by default)',
|
|
78
|
+
'- `bitpub load <name>` — read a slice back',
|
|
79
|
+
'- `bitpub find <term>` — search by name and content (`--all` searches every private slice)',
|
|
80
|
+
'- `bitpub sync` — pull updates from the cloud (`--watch` for a live stream)',
|
|
81
|
+
'- `bitpub delete <name>` — remove (soft-delete, recoverable for 30 days with `--undo`)',
|
|
82
|
+
'',
|
|
83
|
+
'### How the CLI behaves (worth knowing, not commands to you)',
|
|
84
|
+
'',
|
|
85
|
+
'1. **URLs are passed through verbatim.** When a `bitpub://...` URL is given to any command, the CLI uses it as-is. Shortening one to a name before passing it in would re-resolve against the active project instead of the address the URL points at.',
|
|
86
|
+
'2. **`load` falls through on miss.** If `bitpub load <name>` misses in this project but the slice exists elsewhere in private memory, the CLI loads it and prints a stderr note like `(loaded from <full-url> — not in this project)` so you know where it actually lived.',
|
|
87
|
+
'3. **`save` is private by default.** A default-path save lands at `bitpub://private:<owner>/Projects/<this-folder>/...`, encrypted client-side. The CLI never silently writes to a group address — that requires an explicit `bitpub://group:...` URL or a `@team/...` alias.',
|
|
88
|
+
'4. **`save` suggests alternative addresses.** After a default-path save, the CLI prints other private addresses the slice could plausibly live at (`/Memory/...`, `/Inbox/...`, `/Drafts/...`, plus any defined aliases). These are suggestions — the CLI does not act on them. Leading-slash paths resolve against the private root (e.g. `bitpub save /Memory/q3-notes "..."`).',
|
|
89
|
+
'',
|
|
90
|
+
'Anchors and config live in `~/.bitpub/config.json` (nothing is written inside this folder).',
|
|
91
|
+
'Full reference: `~/.claude/skills/bitpub/SKILL.md` (or `bitpub setup skill install` to (re)install).',
|
|
92
|
+
AGENTS_MD_MARKER_END,
|
|
93
|
+
].join('\n');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function escapeRegex(s) {
|
|
97
|
+
return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = { injectAgentsMd, renderAgentsMdSection, AGENTS_MD_MARKER_BEGIN, AGENTS_MD_MARKER_END };
|