hyperspell-brain 0.4.0__tar.gz
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.
- hyperspell_brain-0.4.0/.gitignore +6 -0
- hyperspell_brain-0.4.0/LICENSE +21 -0
- hyperspell_brain-0.4.0/PKG-INFO +217 -0
- hyperspell_brain-0.4.0/README.md +202 -0
- hyperspell_brain-0.4.0/pyproject.toml +43 -0
- hyperspell_brain-0.4.0/src/hyperbrain/__init__.py +3 -0
- hyperspell_brain-0.4.0/src/hyperbrain/cli.py +141 -0
- hyperspell_brain-0.4.0/src/hyperbrain/client.py +93 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/__init__.py +0 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/_query.py +55 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/api.py +89 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/ask.py +79 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/auth.py +43 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/brain.py +147 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/completion.py +70 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/config.py +116 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/connections.py +39 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/doctor.py +67 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/guide.py +132 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/integrations.py +25 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/login.py +145 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/memories.py +233 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/remember.py +91 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/search.py +48 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/structure.py +141 -0
- hyperspell_brain-0.4.0/src/hyperbrain/commands/update.py +184 -0
- hyperspell_brain-0.4.0/src/hyperbrain/config.py +139 -0
- hyperspell_brain-0.4.0/src/hyperbrain/context.py +23 -0
- hyperspell_brain-0.4.0/src/hyperbrain/mcp.py +361 -0
- hyperspell_brain-0.4.0/src/hyperbrain/output.py +174 -0
- hyperspell_brain-0.4.0/tests/test_completion.py +55 -0
- hyperspell_brain-0.4.0/tests/test_doctor.py +51 -0
- hyperspell_brain-0.4.0/tests/test_guide.py +70 -0
- hyperspell_brain-0.4.0/tests/test_mcp.py +329 -0
- hyperspell_brain-0.4.0/tests/test_output.py +125 -0
- hyperspell_brain-0.4.0/tests/test_update.py +169 -0
- hyperspell_brain-0.4.0/uv.lock +1137 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hyperspell
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hyperspell-brain
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: hyperbrain — an agent-first CLI for the Hyperspell company brain
|
|
5
|
+
Author-email: Hyperspell <hello@hyperspell.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Requires-Dist: httpx<1,>=0.27
|
|
10
|
+
Requires-Dist: hyperspell<1,>=0.36
|
|
11
|
+
Requires-Dist: typer<1,>=0.12
|
|
12
|
+
Provides-Extra: mcp
|
|
13
|
+
Requires-Dist: mcp<2,>=1.28; extra == 'mcp'
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# hyperbrain — agent-first CLI for the Hyperspell company brain
|
|
17
|
+
|
|
18
|
+
Hyperspell is the brain for your business — the memory layer that unifies
|
|
19
|
+
everything your company knows. `hyperbrain` is the command line into it: one verb
|
|
20
|
+
that humans *and* agents use to query, write, and synthesize that memory.
|
|
21
|
+
Structured JSON by default, pipe-friendly, no interactive prompts required.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
hyperbrain ask "what's our deployment strategy?" # synthesized answer + sources
|
|
25
|
+
hyperbrain search "rds proxy" --source slack -n 5 # ranked documents, no synthesis
|
|
26
|
+
echo "remember this" | hyperbrain remember # write knowledge in
|
|
27
|
+
hyperbrain brain generate # (re)build the company-brain tree
|
|
28
|
+
hyperbrain memories status # indexing progress per source
|
|
29
|
+
hyperbrain schema # dump the command tree as JSON
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Why this exists
|
|
33
|
+
|
|
34
|
+
If agents are the primary consumer, why a CLI and not just the API? Because the
|
|
35
|
+
CLI is the **universal adapter**. Any agent that can spawn a shell — Claude Code,
|
|
36
|
+
Cursor, a cron job, an autonomous worker you haven't built yet — can use `hyperbrain`
|
|
37
|
+
with zero bespoke integration. No protocol to implement, no server to run, no SDK
|
|
38
|
+
to vendor. Where MCP says "speak this protocol," `hyperbrain` says "here's a verb."
|
|
39
|
+
|
|
40
|
+
It's best understood as one half of a pair:
|
|
41
|
+
|
|
42
|
+
- **Passive context** — the sync daemon writes the synthesized company brain into
|
|
43
|
+
`~/.hyperspell/` and injects it into every agent's `CLAUDE.md` / `AGENTS.md` /
|
|
44
|
+
`.cursorrules`. Agents *start* with company context without asking.
|
|
45
|
+
- **Active query** — when the synced summary isn't enough, the agent calls `hyperbrain`
|
|
46
|
+
to go deeper on demand.
|
|
47
|
+
|
|
48
|
+
Neither alone is the point: the summary is cheap but shallow, `hyperbrain ask` is deep
|
|
49
|
+
but costs a round-trip. Together, an agent has a free baseline and an escape hatch.
|
|
50
|
+
|
|
51
|
+
And note the framing: this is a **brain / memory layer**, not retrieval-as-a-service.
|
|
52
|
+
Anyone can do vector search. The value — and the hard part — is keeping a *living,
|
|
53
|
+
curated, coherent* company memory that's current. `hyperbrain brain generate` (synthesis) and
|
|
54
|
+
`hyperbrain remember` (write-back) point at that; raw `search` is just the primitive
|
|
55
|
+
underneath.
|
|
56
|
+
|
|
57
|
+
## How it's used best
|
|
58
|
+
|
|
59
|
+
**The highest-leverage move is to register `hyperbrain` as a tool your agents can call**,
|
|
60
|
+
and let them decide when to consult company memory. `hyperbrain schema` exists precisely
|
|
61
|
+
so an agent can introspect every capability as JSON.
|
|
62
|
+
|
|
63
|
+
Pick the right verb and effort for the job:
|
|
64
|
+
|
|
65
|
+
| Want | Command | Why |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| A grounded answer | `hyperbrain ask "…"` | synthesizes + cites; defaults to **all connected sources** |
|
|
68
|
+
| Raw material for another tool | `hyperbrain search "…"` | ranked docs, no LLM — the composable primitive |
|
|
69
|
+
| Speed | `-e minimal` / `low` | verbatim retrieval, or a single LLM query-rewrite |
|
|
70
|
+
| Genuinely multi-hop questions | `-e medium` / `high` | agentic refinement loop (up to 3 / 6 rounds) |
|
|
71
|
+
|
|
72
|
+
Lean into composability — this is where it beats a UI:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
hyperbrain ask "what's our deploy process?" -o json | jq -r .answer # clean text for a prompt
|
|
76
|
+
hyperbrain search "rds proxy" --source slack -n 20 | jq '.documents[].title'
|
|
77
|
+
hyperbrain schema | jq # discover every capability
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Close the loop.** A brain only gets smarter if knowledge flows back in. Treat
|
|
81
|
+
`remember` as a habit — decisions, postmortems, the "why" behind a choice — so future
|
|
82
|
+
queries (by humans *or* agents) surface it:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
echo "Decision: standardizing on X because Y" | hyperbrain remember --title "arch decision"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Rule of thumb: scope tight (`--source`, low effort) for speed and precision; go broad
|
|
89
|
+
and high-effort only for hard, cross-source questions. The UI *shows* you the brain —
|
|
90
|
+
the CLI lets your agents **think with it**.
|
|
91
|
+
|
|
92
|
+
## Auth
|
|
93
|
+
|
|
94
|
+
Reuses the sync daemon's `~/.hyperspell/config.toml` — if you've run
|
|
95
|
+
`hyperspell login` or `hyperspell install`, `hyperbrain` just works. Otherwise pass
|
|
96
|
+
`--api-key` or set `HYPERSPELL_API_KEY` (a long-lived API key or a device JWT).
|
|
97
|
+
|
|
98
|
+
Precedence: flags > environment > `~/.hyperspell/config.toml` > defaults.
|
|
99
|
+
|
|
100
|
+
## Agent-first contract
|
|
101
|
+
|
|
102
|
+
- **JSON by default** to stdout when not a TTY (piped/captured); a human table
|
|
103
|
+
on a terminal. Force either with `-o json` / `-o table`.
|
|
104
|
+
- **Diagnostics to stderr**, so stdout is a clean data channel.
|
|
105
|
+
- **Stable exit codes**: `0` ok, `2` usage, `3` auth, `4` not found, `5` API error.
|
|
106
|
+
- **No prompts** — every input is a flag, argument, or stdin.
|
|
107
|
+
|
|
108
|
+
## Install
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
uv tool install . # from a clone; or: uvx --from . hyperbrain ...
|
|
112
|
+
# once published: uv tool install hyperspell-brain / pipx install hyperspell-brain
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The published distribution is `hyperspell-brain` (the bare `hyperbrain` name is
|
|
116
|
+
taken on PyPI by an unrelated project); the installed command is still
|
|
117
|
+
`hyperbrain`.
|
|
118
|
+
|
|
119
|
+
Once installed, upgrade in place with `hyperbrain update` (a thin wrapper over
|
|
120
|
+
`uv tool upgrade`; `--check` reports whether a newer version exists without
|
|
121
|
+
installing, `--reinstall` forces fresh code from a path install). `update`
|
|
122
|
+
requires a `uv tool` install — if you installed via pipx, upgrade with
|
|
123
|
+
`pipx upgrade hyperspell-brain` instead (the command says so rather than
|
|
124
|
+
silently no-op'ing).
|
|
125
|
+
|
|
126
|
+
Shell completion is a generator, not an installer — print the script and put it
|
|
127
|
+
where you want:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
eval "$(hyperbrain completion zsh)" # this session
|
|
131
|
+
hyperbrain completion zsh >> ~/.zshrc # persist (bash/zsh/fish supported)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`hyperbrain doctor` prints resolved endpoint, auth state, version, and config
|
|
135
|
+
path with no network call — the first thing to run when something's off.
|
|
136
|
+
|
|
137
|
+
## For agents
|
|
138
|
+
|
|
139
|
+
- **`hyperbrain help --agent`** — the whole CLI surface as one compact, low-token
|
|
140
|
+
markdown doc (commands + auth tiers + contract + recipes), generated from the
|
|
141
|
+
live command tree. Read it once to self-orient. Scope it with
|
|
142
|
+
`hyperbrain help --agent <command>`.
|
|
143
|
+
- **`--fields a,b,c`** (global) projects every result to those top-level keys;
|
|
144
|
+
**`-q/--quiet`** (global) suppresses stdout so you can branch on the exit code
|
|
145
|
+
alone. Both cut token usage.
|
|
146
|
+
- **`hyperbrain schema`** dumps the full command tree as JSON for programmatic
|
|
147
|
+
introspection.
|
|
148
|
+
|
|
149
|
+
## MCP server (Claude Desktop)
|
|
150
|
+
|
|
151
|
+
Hosts that can't run a CLI or read `CLAUDE.md` — Claude Desktop chief among them —
|
|
152
|
+
reach the brain over MCP instead. The server is an opt-in extra (it pulls
|
|
153
|
+
starlette/uvicorn) and runs over stdio. Its tools come in two tiers, mirroring how
|
|
154
|
+
the product works:
|
|
155
|
+
|
|
156
|
+
- **Local (fast, no API):** `list_context`, `read_context`, `grep_context` read the
|
|
157
|
+
synced `~/.hyperspell` summary off disk (also exposed as `hyperbrain://context/...`
|
|
158
|
+
resources). Read these first.
|
|
159
|
+
- **Source (the full index):** `ask`, `search`, `remember`, `list_memories`,
|
|
160
|
+
`list_connections` go to the Hyperspell index for source-level detail.
|
|
161
|
+
|
|
162
|
+
`brain_status` reports what local context exists and the read-local-first workflow.
|
|
163
|
+
|
|
164
|
+
Crucially, it teaches the host **how** to use the brain. Coding agents learn the
|
|
165
|
+
workflow from the daemon-written `CLAUDE.md` ("read the synced summary first, then
|
|
166
|
+
query"); Claude Desktop never sees that file. So the server detects whether the
|
|
167
|
+
sync daemon's local summary is present and bakes the same ordered methodology into
|
|
168
|
+
its MCP `instructions`, pointing at the actual synced index/sections. A
|
|
169
|
+
`brain_status` tool reports the live state (and the how-to) so a long session can
|
|
170
|
+
re-check after the daemon syncs.
|
|
171
|
+
|
|
172
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"mcpServers": {
|
|
177
|
+
"hyperbrain": {
|
|
178
|
+
"command": "uvx",
|
|
179
|
+
"args": ["--from", "hyperspell-brain[mcp]", "hyperbrain-mcp"],
|
|
180
|
+
"env": { "HYPERSPELL_API_KEY": "hs2-..." }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The API key is read from the config `env` (Desktop users never run
|
|
187
|
+
`hyperspell login`). For local dev, point `--from` at the repo path instead of
|
|
188
|
+
the published dist.
|
|
189
|
+
|
|
190
|
+
## Capability tiers
|
|
191
|
+
|
|
192
|
+
- **Works with a user API key:** `ask`, `search`, `remember`, `memories`,
|
|
193
|
+
`connections`, `integrations`, `brain generate`/`latest`/`get`/`progress`.
|
|
194
|
+
- **Needs an admin JWT (not yet wired):** people, skills, config, canonical docs,
|
|
195
|
+
conflicts, api-keys.
|
|
196
|
+
- **Web-only, no public API (out of scope):** app creation, billing, app settings.
|
|
197
|
+
|
|
198
|
+
## Design notes & honest limitations
|
|
199
|
+
|
|
200
|
+
A few things to know — and a few things worth fixing:
|
|
201
|
+
|
|
202
|
+
- **`ask` needs at least one matching document.** With zero results, the answer
|
|
203
|
+
path currently returns a server-side 500 instead of a clean empty answer. In an
|
|
204
|
+
agent loop this reads as a hard error when it really means "no memories matched."
|
|
205
|
+
- **Deep effort is gated.** `medium` / `high` run an agentic loop behind a per-app
|
|
206
|
+
feature flag. If the flag is off, they *silently* downgrade to a single
|
|
207
|
+
query-rewrite — so `-e high` isn't always doing what it says. Silent downgrade is
|
|
208
|
+
a trust wart for an agent reasoning about cost vs. quality; it should be loud.
|
|
209
|
+
- **Curation is the real product.** Once agents `remember` autonomously, brain
|
|
210
|
+
quality becomes a governance problem — indiscriminate ingestion makes a junk
|
|
211
|
+
drawer, not a brain. The interesting question isn't "can agents write to it" but
|
|
212
|
+
"what's *true* when sources disagree." That's the canonical-docs / conflicts
|
|
213
|
+
machinery, and it's where the moat actually is.
|
|
214
|
+
- **`hyperbrain` and the daemon will likely converge.** They share `~/.hyperspell` and
|
|
215
|
+
half a worldview (both even have `search`). Today they're two tools — passive sync
|
|
216
|
+
(`hyperspell`) and active query (`hyperbrain`) — but one binary doing both is the
|
|
217
|
+
probable end state.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# hyperbrain — agent-first CLI for the Hyperspell company brain
|
|
2
|
+
|
|
3
|
+
Hyperspell is the brain for your business — the memory layer that unifies
|
|
4
|
+
everything your company knows. `hyperbrain` is the command line into it: one verb
|
|
5
|
+
that humans *and* agents use to query, write, and synthesize that memory.
|
|
6
|
+
Structured JSON by default, pipe-friendly, no interactive prompts required.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
hyperbrain ask "what's our deployment strategy?" # synthesized answer + sources
|
|
10
|
+
hyperbrain search "rds proxy" --source slack -n 5 # ranked documents, no synthesis
|
|
11
|
+
echo "remember this" | hyperbrain remember # write knowledge in
|
|
12
|
+
hyperbrain brain generate # (re)build the company-brain tree
|
|
13
|
+
hyperbrain memories status # indexing progress per source
|
|
14
|
+
hyperbrain schema # dump the command tree as JSON
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Why this exists
|
|
18
|
+
|
|
19
|
+
If agents are the primary consumer, why a CLI and not just the API? Because the
|
|
20
|
+
CLI is the **universal adapter**. Any agent that can spawn a shell — Claude Code,
|
|
21
|
+
Cursor, a cron job, an autonomous worker you haven't built yet — can use `hyperbrain`
|
|
22
|
+
with zero bespoke integration. No protocol to implement, no server to run, no SDK
|
|
23
|
+
to vendor. Where MCP says "speak this protocol," `hyperbrain` says "here's a verb."
|
|
24
|
+
|
|
25
|
+
It's best understood as one half of a pair:
|
|
26
|
+
|
|
27
|
+
- **Passive context** — the sync daemon writes the synthesized company brain into
|
|
28
|
+
`~/.hyperspell/` and injects it into every agent's `CLAUDE.md` / `AGENTS.md` /
|
|
29
|
+
`.cursorrules`. Agents *start* with company context without asking.
|
|
30
|
+
- **Active query** — when the synced summary isn't enough, the agent calls `hyperbrain`
|
|
31
|
+
to go deeper on demand.
|
|
32
|
+
|
|
33
|
+
Neither alone is the point: the summary is cheap but shallow, `hyperbrain ask` is deep
|
|
34
|
+
but costs a round-trip. Together, an agent has a free baseline and an escape hatch.
|
|
35
|
+
|
|
36
|
+
And note the framing: this is a **brain / memory layer**, not retrieval-as-a-service.
|
|
37
|
+
Anyone can do vector search. The value — and the hard part — is keeping a *living,
|
|
38
|
+
curated, coherent* company memory that's current. `hyperbrain brain generate` (synthesis) and
|
|
39
|
+
`hyperbrain remember` (write-back) point at that; raw `search` is just the primitive
|
|
40
|
+
underneath.
|
|
41
|
+
|
|
42
|
+
## How it's used best
|
|
43
|
+
|
|
44
|
+
**The highest-leverage move is to register `hyperbrain` as a tool your agents can call**,
|
|
45
|
+
and let them decide when to consult company memory. `hyperbrain schema` exists precisely
|
|
46
|
+
so an agent can introspect every capability as JSON.
|
|
47
|
+
|
|
48
|
+
Pick the right verb and effort for the job:
|
|
49
|
+
|
|
50
|
+
| Want | Command | Why |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| A grounded answer | `hyperbrain ask "…"` | synthesizes + cites; defaults to **all connected sources** |
|
|
53
|
+
| Raw material for another tool | `hyperbrain search "…"` | ranked docs, no LLM — the composable primitive |
|
|
54
|
+
| Speed | `-e minimal` / `low` | verbatim retrieval, or a single LLM query-rewrite |
|
|
55
|
+
| Genuinely multi-hop questions | `-e medium` / `high` | agentic refinement loop (up to 3 / 6 rounds) |
|
|
56
|
+
|
|
57
|
+
Lean into composability — this is where it beats a UI:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
hyperbrain ask "what's our deploy process?" -o json | jq -r .answer # clean text for a prompt
|
|
61
|
+
hyperbrain search "rds proxy" --source slack -n 20 | jq '.documents[].title'
|
|
62
|
+
hyperbrain schema | jq # discover every capability
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Close the loop.** A brain only gets smarter if knowledge flows back in. Treat
|
|
66
|
+
`remember` as a habit — decisions, postmortems, the "why" behind a choice — so future
|
|
67
|
+
queries (by humans *or* agents) surface it:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
echo "Decision: standardizing on X because Y" | hyperbrain remember --title "arch decision"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Rule of thumb: scope tight (`--source`, low effort) for speed and precision; go broad
|
|
74
|
+
and high-effort only for hard, cross-source questions. The UI *shows* you the brain —
|
|
75
|
+
the CLI lets your agents **think with it**.
|
|
76
|
+
|
|
77
|
+
## Auth
|
|
78
|
+
|
|
79
|
+
Reuses the sync daemon's `~/.hyperspell/config.toml` — if you've run
|
|
80
|
+
`hyperspell login` or `hyperspell install`, `hyperbrain` just works. Otherwise pass
|
|
81
|
+
`--api-key` or set `HYPERSPELL_API_KEY` (a long-lived API key or a device JWT).
|
|
82
|
+
|
|
83
|
+
Precedence: flags > environment > `~/.hyperspell/config.toml` > defaults.
|
|
84
|
+
|
|
85
|
+
## Agent-first contract
|
|
86
|
+
|
|
87
|
+
- **JSON by default** to stdout when not a TTY (piped/captured); a human table
|
|
88
|
+
on a terminal. Force either with `-o json` / `-o table`.
|
|
89
|
+
- **Diagnostics to stderr**, so stdout is a clean data channel.
|
|
90
|
+
- **Stable exit codes**: `0` ok, `2` usage, `3` auth, `4` not found, `5` API error.
|
|
91
|
+
- **No prompts** — every input is a flag, argument, or stdin.
|
|
92
|
+
|
|
93
|
+
## Install
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
uv tool install . # from a clone; or: uvx --from . hyperbrain ...
|
|
97
|
+
# once published: uv tool install hyperspell-brain / pipx install hyperspell-brain
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The published distribution is `hyperspell-brain` (the bare `hyperbrain` name is
|
|
101
|
+
taken on PyPI by an unrelated project); the installed command is still
|
|
102
|
+
`hyperbrain`.
|
|
103
|
+
|
|
104
|
+
Once installed, upgrade in place with `hyperbrain update` (a thin wrapper over
|
|
105
|
+
`uv tool upgrade`; `--check` reports whether a newer version exists without
|
|
106
|
+
installing, `--reinstall` forces fresh code from a path install). `update`
|
|
107
|
+
requires a `uv tool` install — if you installed via pipx, upgrade with
|
|
108
|
+
`pipx upgrade hyperspell-brain` instead (the command says so rather than
|
|
109
|
+
silently no-op'ing).
|
|
110
|
+
|
|
111
|
+
Shell completion is a generator, not an installer — print the script and put it
|
|
112
|
+
where you want:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
eval "$(hyperbrain completion zsh)" # this session
|
|
116
|
+
hyperbrain completion zsh >> ~/.zshrc # persist (bash/zsh/fish supported)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`hyperbrain doctor` prints resolved endpoint, auth state, version, and config
|
|
120
|
+
path with no network call — the first thing to run when something's off.
|
|
121
|
+
|
|
122
|
+
## For agents
|
|
123
|
+
|
|
124
|
+
- **`hyperbrain help --agent`** — the whole CLI surface as one compact, low-token
|
|
125
|
+
markdown doc (commands + auth tiers + contract + recipes), generated from the
|
|
126
|
+
live command tree. Read it once to self-orient. Scope it with
|
|
127
|
+
`hyperbrain help --agent <command>`.
|
|
128
|
+
- **`--fields a,b,c`** (global) projects every result to those top-level keys;
|
|
129
|
+
**`-q/--quiet`** (global) suppresses stdout so you can branch on the exit code
|
|
130
|
+
alone. Both cut token usage.
|
|
131
|
+
- **`hyperbrain schema`** dumps the full command tree as JSON for programmatic
|
|
132
|
+
introspection.
|
|
133
|
+
|
|
134
|
+
## MCP server (Claude Desktop)
|
|
135
|
+
|
|
136
|
+
Hosts that can't run a CLI or read `CLAUDE.md` — Claude Desktop chief among them —
|
|
137
|
+
reach the brain over MCP instead. The server is an opt-in extra (it pulls
|
|
138
|
+
starlette/uvicorn) and runs over stdio. Its tools come in two tiers, mirroring how
|
|
139
|
+
the product works:
|
|
140
|
+
|
|
141
|
+
- **Local (fast, no API):** `list_context`, `read_context`, `grep_context` read the
|
|
142
|
+
synced `~/.hyperspell` summary off disk (also exposed as `hyperbrain://context/...`
|
|
143
|
+
resources). Read these first.
|
|
144
|
+
- **Source (the full index):** `ask`, `search`, `remember`, `list_memories`,
|
|
145
|
+
`list_connections` go to the Hyperspell index for source-level detail.
|
|
146
|
+
|
|
147
|
+
`brain_status` reports what local context exists and the read-local-first workflow.
|
|
148
|
+
|
|
149
|
+
Crucially, it teaches the host **how** to use the brain. Coding agents learn the
|
|
150
|
+
workflow from the daemon-written `CLAUDE.md` ("read the synced summary first, then
|
|
151
|
+
query"); Claude Desktop never sees that file. So the server detects whether the
|
|
152
|
+
sync daemon's local summary is present and bakes the same ordered methodology into
|
|
153
|
+
its MCP `instructions`, pointing at the actual synced index/sections. A
|
|
154
|
+
`brain_status` tool reports the live state (and the how-to) so a long session can
|
|
155
|
+
re-check after the daemon syncs.
|
|
156
|
+
|
|
157
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"mcpServers": {
|
|
162
|
+
"hyperbrain": {
|
|
163
|
+
"command": "uvx",
|
|
164
|
+
"args": ["--from", "hyperspell-brain[mcp]", "hyperbrain-mcp"],
|
|
165
|
+
"env": { "HYPERSPELL_API_KEY": "hs2-..." }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The API key is read from the config `env` (Desktop users never run
|
|
172
|
+
`hyperspell login`). For local dev, point `--from` at the repo path instead of
|
|
173
|
+
the published dist.
|
|
174
|
+
|
|
175
|
+
## Capability tiers
|
|
176
|
+
|
|
177
|
+
- **Works with a user API key:** `ask`, `search`, `remember`, `memories`,
|
|
178
|
+
`connections`, `integrations`, `brain generate`/`latest`/`get`/`progress`.
|
|
179
|
+
- **Needs an admin JWT (not yet wired):** people, skills, config, canonical docs,
|
|
180
|
+
conflicts, api-keys.
|
|
181
|
+
- **Web-only, no public API (out of scope):** app creation, billing, app settings.
|
|
182
|
+
|
|
183
|
+
## Design notes & honest limitations
|
|
184
|
+
|
|
185
|
+
A few things to know — and a few things worth fixing:
|
|
186
|
+
|
|
187
|
+
- **`ask` needs at least one matching document.** With zero results, the answer
|
|
188
|
+
path currently returns a server-side 500 instead of a clean empty answer. In an
|
|
189
|
+
agent loop this reads as a hard error when it really means "no memories matched."
|
|
190
|
+
- **Deep effort is gated.** `medium` / `high` run an agentic loop behind a per-app
|
|
191
|
+
feature flag. If the flag is off, they *silently* downgrade to a single
|
|
192
|
+
query-rewrite — so `-e high` isn't always doing what it says. Silent downgrade is
|
|
193
|
+
a trust wart for an agent reasoning about cost vs. quality; it should be loud.
|
|
194
|
+
- **Curation is the real product.** Once agents `remember` autonomously, brain
|
|
195
|
+
quality becomes a governance problem — indiscriminate ingestion makes a junk
|
|
196
|
+
drawer, not a brain. The interesting question isn't "can agents write to it" but
|
|
197
|
+
"what's *true* when sources disagree." That's the canonical-docs / conflicts
|
|
198
|
+
machinery, and it's where the moat actually is.
|
|
199
|
+
- **`hyperbrain` and the daemon will likely converge.** They share `~/.hyperspell` and
|
|
200
|
+
half a worldview (both even have `search`). Today they're two tools — passive sync
|
|
201
|
+
(`hyperspell`) and active query (`hyperbrain`) — but one binary doing both is the
|
|
202
|
+
probable end state.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
# Distribution name is `hyperspell-brain`, not `hyperbrain`: the bare
|
|
3
|
+
# `hyperbrain` name is taken on PyPI by an unrelated 2020 project. The console
|
|
4
|
+
# script stays `hyperbrain` (see [project.scripts]) and the import package stays
|
|
5
|
+
# `hyperbrain` (see tool.hatch.build) — only the published dist name changes.
|
|
6
|
+
name = "hyperspell-brain"
|
|
7
|
+
version = "0.4.0"
|
|
8
|
+
description = "hyperbrain — an agent-first CLI for the Hyperspell company brain"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{ name = "Hyperspell", email = "hello@hyperspell.com" }]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"hyperspell>=0.36,<1",
|
|
15
|
+
"typer>=0.12,<1",
|
|
16
|
+
"httpx>=0.27,<1",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# The MCP server (for Claude Desktop and other MCP hosts) is opt-in: it pulls
|
|
20
|
+
# starlette/uvicorn/etc., which the common CLI install doesn't need. Install
|
|
21
|
+
# `hyperspell-brain[mcp]` to get the `hyperbrain-mcp` entry point.
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
mcp = ["mcp>=1.28,<2"]
|
|
24
|
+
|
|
25
|
+
[dependency-groups]
|
|
26
|
+
dev = [
|
|
27
|
+
"pytest>=8,<9",
|
|
28
|
+
"mcp>=1.28,<2", # the MCP tests import hyperbrain.mcp, which needs the extra
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
hyperbrain = "hyperbrain.cli:app"
|
|
33
|
+
hyperbrain-mcp = "hyperbrain.mcp:main"
|
|
34
|
+
|
|
35
|
+
[build-system]
|
|
36
|
+
requires = ["hatchling"]
|
|
37
|
+
build-backend = "hatchling.build"
|
|
38
|
+
|
|
39
|
+
[tool.hatch.build.targets.wheel]
|
|
40
|
+
packages = ["src/hyperbrain"]
|
|
41
|
+
|
|
42
|
+
[tool.ruff]
|
|
43
|
+
line-length = 100
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""hyperbrain — agent-first CLI for the Hyperspell company brain.
|
|
2
|
+
|
|
3
|
+
Root command: wires global options into a per-invocation AppCtx, then dispatches
|
|
4
|
+
to the command modules. Designed so an agent can call any subcommand
|
|
5
|
+
non-interactively and parse JSON from stdout.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Optional
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
|
|
14
|
+
from . import __version__, config
|
|
15
|
+
from .context import AppCtx
|
|
16
|
+
from .output import FORMAT_OPTION, Format, emit, pick, set_output_options
|
|
17
|
+
from .commands import api as api_cmd
|
|
18
|
+
from .commands import ask as ask_cmd
|
|
19
|
+
from .commands import auth as auth_cmd
|
|
20
|
+
from .commands import brain as brain_cmd
|
|
21
|
+
from .commands import completion as completion_cmd
|
|
22
|
+
from .commands import config as config_cmd
|
|
23
|
+
from .commands import connections as connections_cmd
|
|
24
|
+
from .commands import doctor as doctor_cmd
|
|
25
|
+
from .commands import guide as guide_cmd
|
|
26
|
+
from .commands import integrations as integrations_cmd
|
|
27
|
+
from .commands import login as login_cmd
|
|
28
|
+
from .commands import memories as memories_cmd
|
|
29
|
+
from .commands import remember as remember_cmd
|
|
30
|
+
from .commands import search as search_cmd
|
|
31
|
+
from .commands import structure as structure_cmd
|
|
32
|
+
from .commands import update as update_cmd
|
|
33
|
+
|
|
34
|
+
app = typer.Typer(
|
|
35
|
+
name="hyperbrain",
|
|
36
|
+
help="Agent-first CLI for the Hyperspell company brain. JSON by default; pipe-friendly.",
|
|
37
|
+
no_args_is_help=True,
|
|
38
|
+
add_completion=False,
|
|
39
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _version(value: bool) -> None:
|
|
44
|
+
if value:
|
|
45
|
+
typer.echo(__version__)
|
|
46
|
+
raise typer.Exit()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@app.callback()
|
|
50
|
+
def main(
|
|
51
|
+
ctx: typer.Context,
|
|
52
|
+
api_key: Optional[str] = typer.Option(
|
|
53
|
+
None, "--api-key", envvar="HYPERSPELL_API_KEY", help="API key (or device JWT)."
|
|
54
|
+
),
|
|
55
|
+
api_url: Optional[str] = typer.Option(
|
|
56
|
+
None, "--api-url", envvar="HYPERSPELL_BASE_URL", help="API base URL."
|
|
57
|
+
),
|
|
58
|
+
as_user: Optional[str] = typer.Option(
|
|
59
|
+
None, "--as-user", help="Act as this user (X-As-User; API-key auth only)."
|
|
60
|
+
),
|
|
61
|
+
output_format: Format = typer.Option(
|
|
62
|
+
Format.AUTO,
|
|
63
|
+
"--format",
|
|
64
|
+
"-o",
|
|
65
|
+
help="Output format: auto (table on TTY, else json), json, table.",
|
|
66
|
+
),
|
|
67
|
+
fields: Optional[str] = typer.Option(
|
|
68
|
+
None,
|
|
69
|
+
"--fields",
|
|
70
|
+
help="Comma-separated top-level keys to keep in the output (token economy).",
|
|
71
|
+
),
|
|
72
|
+
quiet: bool = typer.Option(
|
|
73
|
+
False,
|
|
74
|
+
"--quiet",
|
|
75
|
+
"-q",
|
|
76
|
+
help="Suppress the stdout data channel; branch on the exit code instead.",
|
|
77
|
+
),
|
|
78
|
+
_v: bool = typer.Option(
|
|
79
|
+
False, "--version", callback=_version, is_eager=True, help="Show version and exit."
|
|
80
|
+
),
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Resolve credentials/endpoint once and stash them for subcommands."""
|
|
83
|
+
set_output_options(fields=fields, quiet=quiet)
|
|
84
|
+
ctx.obj = AppCtx(
|
|
85
|
+
resolved=config.resolve(api_key=api_key, api_url=api_url, as_user=as_user),
|
|
86
|
+
fmt=output_format,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# Top-level verbs.
|
|
91
|
+
app.command()(login_cmd.login)
|
|
92
|
+
app.command()(ask_cmd.ask)
|
|
93
|
+
app.command()(search_cmd.search)
|
|
94
|
+
app.command()(remember_cmd.remember)
|
|
95
|
+
app.command(name="api")(api_cmd.api)
|
|
96
|
+
app.command()(update_cmd.update)
|
|
97
|
+
app.command()(doctor_cmd.doctor)
|
|
98
|
+
app.command()(completion_cmd.completion)
|
|
99
|
+
app.command(name="help")(guide_cmd.help)
|
|
100
|
+
|
|
101
|
+
# Grouped nouns.
|
|
102
|
+
app.add_typer(memories_cmd.app, name="memories")
|
|
103
|
+
app.add_typer(connections_cmd.app, name="connections")
|
|
104
|
+
app.add_typer(integrations_cmd.app, name="integrations")
|
|
105
|
+
app.add_typer(brain_cmd.app, name="brain")
|
|
106
|
+
app.add_typer(structure_cmd.app, name="structure")
|
|
107
|
+
app.add_typer(config_cmd.app, name="config")
|
|
108
|
+
app.add_typer(auth_cmd.app, name="auth")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _describe(cmd: Any, name: str) -> dict[str, Any]:
|
|
112
|
+
"""Recursively describe a click command tree using duck-typing (no click import)."""
|
|
113
|
+
node: dict[str, Any] = {"name": name, "help": (getattr(cmd, "help", "") or "").strip()}
|
|
114
|
+
params = []
|
|
115
|
+
for p in getattr(cmd, "params", []):
|
|
116
|
+
kind = getattr(p, "param_type_name", "parameter") # 'option' | 'argument'
|
|
117
|
+
entry: dict[str, Any] = {"name": p.name, "kind": kind, "required": bool(p.required)}
|
|
118
|
+
if kind == "option":
|
|
119
|
+
entry["flags"] = list(getattr(p, "opts", []))
|
|
120
|
+
entry["help"] = getattr(p, "help", "") or ""
|
|
121
|
+
params.append(entry)
|
|
122
|
+
if params:
|
|
123
|
+
node["params"] = params
|
|
124
|
+
subcommands = getattr(cmd, "commands", None) # dict on click Groups
|
|
125
|
+
if isinstance(subcommands, dict):
|
|
126
|
+
node["commands"] = [_describe(sub, sub_name) for sub_name, sub in subcommands.items()]
|
|
127
|
+
return node
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@app.command()
|
|
131
|
+
def schema(
|
|
132
|
+
ctx: typer.Context,
|
|
133
|
+
fmt: Optional[Format] = FORMAT_OPTION,
|
|
134
|
+
) -> None:
|
|
135
|
+
"""Dump the full command tree as JSON, so an agent can introspect capabilities."""
|
|
136
|
+
root = typer.main.get_command(app)
|
|
137
|
+
emit(_describe(root, "hyperbrain"), pick(ctx, fmt))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
app()
|