hyperstack-core 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CascadeAI
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.
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # hyperstack-core
2
+
3
+ Typed graph memory for AI agents. Replace `GOALS.md` + `DECISIONS.md` with queryable cards and relations.
4
+
5
+ ```
6
+ npm i hyperstack-core
7
+ npx hyperstack-core init openclaw-multiagent
8
+ ```
9
+
10
+ ## The Problem
11
+
12
+ OpenClaw multi-agent setups use markdown files for coordination:
13
+
14
+ ```
15
+ # DECISIONS.md (append-only)
16
+ - 2026-02-15: Use Clerk for auth (coder-agent)
17
+ - 2026-02-15: Deploy needs auth migration first (deploy-agent)
18
+ - 2026-02-16: Migration blocks production deploy (ops-agent)
19
+ ```
20
+
21
+ Try answering: **"What blocks the production deploy?"**
22
+
23
+ With markdown: `grep -r "blocks.*deploy" *.md` — manual, fragile, returns text blobs.
24
+
25
+ ## The Solution
26
+
27
+ ```js
28
+ import { HyperStackClient } from "hyperstack-core";
29
+
30
+ const hs = new HyperStackClient({ apiKey: "hs_..." });
31
+
32
+ // Coder agent records a decision
33
+ await hs.decide({
34
+ slug: "use-clerk",
35
+ title: "Use Clerk for auth",
36
+ body: "Better DX, lower cost, native Next.js support",
37
+ decidedBy: "agent-coder",
38
+ affects: ["auth-api"],
39
+ });
40
+
41
+ // Deploy agent records a blocker
42
+ await hs.store({
43
+ slug: "migration-23",
44
+ title: "Auth migration to Clerk",
45
+ cardType: "task",
46
+ links: [
47
+ { target: "deploy-prod", relation: "blocks" },
48
+ { target: "use-clerk", relation: "depends_on" },
49
+ ],
50
+ });
51
+
52
+ // Ops agent asks: what blocks deploy?
53
+ const result = await hs.blockers("deploy-prod");
54
+ // → { blockers: [{ slug: "migration-23", title: "Auth migration to Clerk" }] }
55
+ ```
56
+
57
+ **Typed relations, not text blobs.** `task→blocks→deploy` is queryable. A paragraph in DECISIONS.md is not.
58
+
59
+ ## OpenClaw Integration
60
+
61
+ ```js
62
+ import { createOpenClawAdapter } from "hyperstack-core/adapters/openclaw";
63
+
64
+ // Each agent gets its own adapter
65
+ const researcher = createOpenClawAdapter({ agentId: "researcher" });
66
+ const builder = createOpenClawAdapter({ agentId: "builder" });
67
+
68
+ // Register on session start
69
+ await researcher.onSessionStart({
70
+ agentName: "Research Agent",
71
+ agentRole: "Investigate questions, store findings as context cards",
72
+ });
73
+
74
+ // Use tools in agent logic
75
+ await researcher.tools.hs_store({
76
+ slug: "finding-clerk-pricing",
77
+ title: "Clerk pricing analysis",
78
+ body: "Free for 10K MAU, $0.02/MAU after. Cheaper than Auth0 at our scale.",
79
+ type: "context",
80
+ links: "use-clerk:related",
81
+ });
82
+
83
+ // Builder queries shared knowledge
84
+ const blockers = await builder.tools.hs_blockers({ slug: "deploy-prod" });
85
+ // → "1 blocker: [migration-23] Auth migration to Clerk"
86
+ ```
87
+
88
+ ## CLI
89
+
90
+ ```bash
91
+ # Initialize with multi-agent template
92
+ npx hyperstack-core init openclaw-multiagent
93
+
94
+ # Store cards
95
+ npx hyperstack-core store --slug "use-clerk" --title "Use Clerk" --type decision
96
+
97
+ # Record decisions
98
+ npx hyperstack-core decide --slug "use-clerk" --title "Use Clerk" --rationale "Better DX"
99
+
100
+ # Check blockers
101
+ npx hyperstack-core blockers deploy-prod
102
+
103
+ # Traverse graph
104
+ npx hyperstack-core graph auth-api --depth 2
105
+
106
+ # Search
107
+ npx hyperstack-core search "authentication setup"
108
+
109
+ # List all cards
110
+ npx hyperstack-core list
111
+ ```
112
+
113
+ ## Why Not Mem0/Cognee?
114
+
115
+ | | hyperstack-core | Mem0 | Cognee |
116
+ |--|---|---|---|
117
+ | "What blocks deploy?" | Exact: 2 typed blockers | Fuzzy: 17 similar tasks | Generic entities |
118
+ | Relations | `task→blocks→deploy` (typed) | Auto-extracted (hallucinated) | Generic graph |
119
+ | Cost per op | **$0** (deterministic) | ~$0.002 (LLM extraction) | ~$0.002 |
120
+ | Multi-agent | Built-in agent tagging | Shared userId issues | No agent awareness |
121
+ | Setup | `npm i` + 1 env var | Docker + config | Docker + Neo4j |
122
+
123
+ Mem0 finds "similar" cards. HyperStack finds **exactly** what blocks task #42.
124
+
125
+ ## How It Works
126
+
127
+ Cards are typed objects with explicit relations:
128
+
129
+ ```
130
+ [task:deploy-prod] "Deploy to production"
131
+ ←blocks— [task:migration-23] "Auth migration to Clerk"
132
+ ←blocks— [blocker:staging-tests] "Staging tests failing"
133
+ —assigned_to→ [agent:deploy-agent]
134
+ —depends_on→ [decision:use-clerk]
135
+ ```
136
+
137
+ Every card stores: slug, title, body, cardType, links (typed relations), keywords, meta.
138
+ Every relation is explicit — no LLM extraction, no hallucinated connections.
139
+
140
+ Backed by HyperStack API (Neon PostgreSQL + pgvector for hybrid search).
141
+
142
+ ## Setup
143
+
144
+ 1. Get a free API key: [cascadeai.dev/hyperstack](https://cascadeai.dev/hyperstack)
145
+ 2. `export HYPERSTACK_API_KEY=hs_your_key`
146
+ 3. `npm i hyperstack-core`
147
+ 4. `npx hyperstack-core init openclaw-multiagent`
148
+
149
+ Free tier: 10 cards, keyword search.
150
+ Pro ($29/mo): 100 cards, graph traversal, time-travel, semantic search.
151
+
152
+ ## License
153
+
154
+ MIT
package/SKILL.md ADDED
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: hyperstack
3
+ description: "Typed graph memory for multi-agent coordination. Replace GOALS.md + DECISIONS.md with queryable cards and relations. Ask 'what blocks task X?' and get exact answers, not text blobs."
4
+ user-invocable: true
5
+ homepage: https://cascadeai.dev/hyperstack
6
+ metadata:
7
+ openclaw:
8
+ emoji: "🃏"
9
+ requires:
10
+ env:
11
+ - HYPERSTACK_API_KEY
12
+ primaryEnv: HYPERSTACK_API_KEY
13
+ ---
14
+
15
+ # HyperStack — Typed Graph Memory for Multi-Agent Coordination
16
+
17
+ ## What this does
18
+
19
+ Replaces markdown-file coordination (GOALS.md, DECISIONS.md, WORKING.md) with a typed knowledge graph that any agent can query.
20
+
21
+ **Before** (current OpenClaw multi-agent):
22
+ ```
23
+ # DECISIONS.md (append-only)
24
+ - 2026-02-15: Use Clerk for auth (coder-agent)
25
+ - 2026-02-16: Migration blocks production deploy (ops-agent)
26
+ ```
27
+ "What blocks deploy?" → `grep -r "blocks.*deploy" *.md` → manual, fragile
28
+
29
+ **After** (HyperStack):
30
+ ```
31
+ "What blocks deploy?" → hs_blockers deploy-prod → [migration-23] Auth migration to Clerk
32
+ ```
33
+
34
+ Typed relations. Exact answers. Zero LLM cost.
35
+
36
+ ## Tools
37
+
38
+ ### hs_search
39
+ Search the shared knowledge graph.
40
+ ```
41
+ hs_search({ query: "authentication setup" })
42
+ ```
43
+
44
+ ### hs_store
45
+ Store a card in the graph. Auto-tags with your agent ID.
46
+ ```
47
+ hs_store({
48
+ slug: "use-clerk",
49
+ title: "Use Clerk for auth",
50
+ body: "Better DX, lower cost, native Next.js support",
51
+ type: "decision",
52
+ links: "auth-api:triggers,alice:decided"
53
+ })
54
+ ```
55
+
56
+ ### hs_decide
57
+ Record a decision with full provenance — who decided, what it affects, what it blocks.
58
+ ```
59
+ hs_decide({
60
+ slug: "use-clerk",
61
+ title: "Use Clerk for auth",
62
+ rationale: "Better DX, lower cost vs Auth0",
63
+ affects: "auth-api,user-service",
64
+ blocks: ""
65
+ })
66
+ ```
67
+
68
+ ### hs_blockers
69
+ Check what blocks a task/card. Returns exact typed blockers, not fuzzy search results.
70
+ ```
71
+ hs_blockers({ slug: "deploy-prod" })
72
+ → "1 blocker: [migration-23] Auth migration to Clerk"
73
+ ```
74
+
75
+ ### hs_graph
76
+ Traverse the knowledge graph from a starting card. See connections, ownership, dependencies.
77
+ ```
78
+ hs_graph({ from: "auth-api", depth: 2 })
79
+ → nodes: [auth-api, use-clerk, migration-23, alice]
80
+ → edges: [auth-api→triggers→use-clerk, migration-23→blocks→deploy-prod]
81
+ ```
82
+
83
+ ### hs_my_cards
84
+ List all cards created by this agent.
85
+ ```
86
+ hs_my_cards()
87
+ → "3 cards by agent researcher: [finding-clerk-pricing] [finding-auth0-limits] [finding-nextauth-deprecated]"
88
+ ```
89
+
90
+ ## Multi-Agent Setup
91
+
92
+ Each agent gets its own ID. Cards are auto-tagged so you can see who created what.
93
+
94
+ Recommended roles:
95
+ - **coordinator**: Routes tasks, monitors blockers (`hs_blockers`, `hs_graph`, `hs_decide`)
96
+ - **researcher**: Investigates, stores findings (`hs_search`, `hs_store`)
97
+ - **builder**: Implements, records tech decisions (`hs_store`, `hs_decide`, `hs_blockers`)
98
+
99
+ ## Setup
100
+
101
+ 1. Get free API key: https://cascadeai.dev/hyperstack
102
+ 2. Set `HYPERSTACK_API_KEY=hs_your_key` in your OpenClaw env
103
+ 3. Tools are available immediately
104
+
105
+ Free: 10 cards, keyword search.
106
+ Pro ($29/mo): 100 cards, graph traversal, semantic search, time-travel debugging.
107
+
108
+ ## When to use
109
+
110
+ - **Start of session**: `hs_search` for relevant context
111
+ - **Decision made**: `hs_decide` with rationale and links
112
+ - **Task blocked**: `hs_store` with `blocks` relation
113
+ - **Before starting work**: `hs_blockers` to check dependencies
114
+ - **New finding**: `hs_store` as context card
115
+
116
+ ## Data safety
117
+
118
+ NEVER store passwords, API keys, tokens, PII, or credentials. Cards should be safe in a data breach. Always confirm with user before storing.
@@ -0,0 +1,221 @@
1
+ /**
2
+ * hyperstack-core/adapters/openclaw.js
3
+ *
4
+ * OpenClaw adapter for HyperStack.
5
+ * Replaces GOALS.md / DECISIONS.md with typed graph memory.
6
+ *
7
+ * Usage in OpenClaw config (openclaw.json):
8
+ * {
9
+ * "skills": ["hyperstack-core/adapters/openclaw"],
10
+ * "env": {
11
+ * "HYPERSTACK_API_KEY": "hs_your_key"
12
+ * }
13
+ * }
14
+ *
15
+ * Or use programmatically:
16
+ * import { createOpenClawAdapter } from "hyperstack-core/adapters/openclaw";
17
+ * const adapter = createOpenClawAdapter({ agentId: "researcher" });
18
+ */
19
+
20
+ import { HyperStackClient } from "../src/client.js";
21
+
22
+ /**
23
+ * Create an OpenClaw-compatible adapter that provides tools
24
+ * for multi-agent coordination via HyperStack.
25
+ *
26
+ * @param {object} opts
27
+ * @param {string} opts.agentId — this agent's unique ID
28
+ * @param {string} [opts.apiKey] — HyperStack API key
29
+ * @param {string} [opts.workspace] — workspace slug
30
+ */
31
+ function createOpenClawAdapter(opts = {}) {
32
+ const agentId = opts.agentId || process.env.OPENCLAW_AGENT_ID || "main";
33
+
34
+ const client = new HyperStackClient({
35
+ apiKey: opts.apiKey,
36
+ workspace: opts.workspace,
37
+ agentId,
38
+ });
39
+
40
+ return {
41
+ client,
42
+ agentId,
43
+
44
+ /**
45
+ * Tools that get exposed to the OpenClaw agent.
46
+ * These can be called via OpenClaw's tool system.
47
+ */
48
+ tools: {
49
+ /**
50
+ * Search the shared knowledge graph.
51
+ */
52
+ async hs_search({ query }) {
53
+ const result = await client.search(query);
54
+ const cards = result.results || [];
55
+ if (!cards.length) return { text: "No matching cards found." };
56
+
57
+ return {
58
+ text: cards.slice(0, 5).map(c => {
59
+ let line = `[${c.slug}] ${c.title} (${c.cardType || "general"})`;
60
+ if (c.body) line += `\n ${c.body.slice(0, 200)}`;
61
+ if (c.links?.length) {
62
+ line += `\n Links: ${c.links.map(l => `${l.relation}→${l.target}`).join(", ")}`;
63
+ }
64
+ return line;
65
+ }).join("\n\n"),
66
+ cards,
67
+ };
68
+ },
69
+
70
+ /**
71
+ * Store a card in the shared graph. Auto-tags with agent ID.
72
+ */
73
+ async hs_store({ slug, title, body, type, links, keywords }) {
74
+ const parsedLinks = [];
75
+ if (links) {
76
+ // Accept "target:relation,target:relation" format
77
+ for (const l of (typeof links === "string" ? links.split(",") : links)) {
78
+ if (typeof l === "string") {
79
+ const [target, relation] = l.trim().split(":");
80
+ parsedLinks.push({ target: target.trim(), relation: (relation || "related").trim() });
81
+ } else {
82
+ parsedLinks.push(l);
83
+ }
84
+ }
85
+ }
86
+
87
+ const result = await client.store({
88
+ slug,
89
+ title,
90
+ body: body || "",
91
+ cardType: type || "general",
92
+ keywords: typeof keywords === "string" ? keywords.split(",").map(k => k.trim()) : (keywords || []),
93
+ links: parsedLinks,
94
+ });
95
+
96
+ return {
97
+ text: `${result.updated ? "Updated" : "Created"} [${slug}]: ${title}`,
98
+ result,
99
+ };
100
+ },
101
+
102
+ /**
103
+ * Record a decision with full provenance.
104
+ */
105
+ async hs_decide({ slug, title, rationale, affects, blocks }) {
106
+ const result = await client.decide({
107
+ slug,
108
+ title,
109
+ body: rationale,
110
+ decidedBy: `agent-${agentId}`,
111
+ affects: affects ? (typeof affects === "string" ? affects.split(",").map(s => s.trim()) : affects) : [],
112
+ blocks: blocks ? (typeof blocks === "string" ? blocks.split(",").map(s => s.trim()) : blocks) : [],
113
+ });
114
+
115
+ return {
116
+ text: `Decision recorded: [${slug}] ${title} (by ${agentId})`,
117
+ result,
118
+ };
119
+ },
120
+
121
+ /**
122
+ * Check what blocks a task/card.
123
+ */
124
+ async hs_blockers({ slug }) {
125
+ const result = await client.blockers(slug);
126
+ const blockers = result.blockers || [];
127
+
128
+ if (!blockers.length) {
129
+ return { text: `Nothing blocks [${slug}].`, blockers: [] };
130
+ }
131
+
132
+ return {
133
+ text: `${blockers.length} blocker(s) for [${slug}]:\n` +
134
+ blockers.map(b => ` [${b.slug}] ${b.title || "?"}`).join("\n"),
135
+ blockers,
136
+ };
137
+ },
138
+
139
+ /**
140
+ * Traverse the graph from a card.
141
+ */
142
+ async hs_graph({ from, depth, relation }) {
143
+ const result = await client.graph(from, {
144
+ depth: depth || 2,
145
+ relation: relation || undefined,
146
+ });
147
+
148
+ const nodes = result.nodes || [];
149
+ const edges = result.edges || [];
150
+
151
+ if (!nodes.length) {
152
+ return { text: `No graph found from [${from}].`, nodes: [], edges: [] };
153
+ }
154
+
155
+ let text = `Graph from [${from}]: ${nodes.length} nodes, ${edges.length} edges\n\n`;
156
+ text += "Nodes:\n" + nodes.map(n =>
157
+ ` [${n.slug}] ${n.title || "?"} (${n.cardType || "?"})`
158
+ ).join("\n");
159
+ text += "\n\nEdges:\n" + edges.map(e =>
160
+ ` ${e.from} --${e.relation}--> ${e.to}`
161
+ ).join("\n");
162
+
163
+ return { text, nodes, edges };
164
+ },
165
+
166
+ /**
167
+ * List all cards by this agent.
168
+ */
169
+ async hs_my_cards() {
170
+ const result = await client.agentCards(agentId);
171
+ const cards = result.results || [];
172
+
173
+ return {
174
+ text: `${cards.length} cards by agent "${agentId}":\n` +
175
+ cards.map(c => ` [${c.slug}] ${c.title}`).join("\n"),
176
+ cards,
177
+ };
178
+ },
179
+ },
180
+
181
+ /**
182
+ * Hook: called when agent session starts.
183
+ * Registers the agent and loads relevant context.
184
+ */
185
+ async onSessionStart({ agentName, agentRole }) {
186
+ // Register this agent in the graph
187
+ await client.registerAgent({
188
+ id: agentId,
189
+ name: agentName || agentId,
190
+ role: agentRole || "OpenClaw agent",
191
+ });
192
+
193
+ // Load recent context for this agent
194
+ const context = await client.search(`agent:${agentId}`);
195
+ return {
196
+ cards: context.results || [],
197
+ text: `HyperStack: ${(context.results || []).length} cards loaded for agent "${agentId}"`,
198
+ };
199
+ },
200
+
201
+ /**
202
+ * Hook: called when agent session ends.
203
+ * Good place to save working state.
204
+ */
205
+ async onSessionEnd({ summary }) {
206
+ if (summary) {
207
+ await client.store({
208
+ slug: `session-${agentId}-${Date.now()}`,
209
+ title: `Session summary (${agentId})`,
210
+ body: summary.slice(0, 500),
211
+ cardType: "event",
212
+ stack: "general",
213
+ keywords: ["session", "summary"],
214
+ });
215
+ }
216
+ },
217
+ };
218
+ }
219
+
220
+ export { createOpenClawAdapter };
221
+ export default createOpenClawAdapter;