iranti 0.3.20 → 0.3.22
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 +160 -783
- package/dist/scripts/iranti-cli.js +138 -0
- package/dist/scripts/iranti-mcp.js +3 -3
- package/dist/src/api/server.js +30 -1
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/attendant/AttendantInstance.d.ts +9 -1
- package/dist/src/attendant/AttendantInstance.d.ts.map +1 -1
- package/dist/src/attendant/AttendantInstance.js +61 -6
- package/dist/src/attendant/AttendantInstance.js.map +1 -1
- package/dist/src/lib/check-bootstrap-state.d.ts +2 -0
- package/dist/src/lib/check-bootstrap-state.d.ts.map +1 -0
- package/dist/src/lib/check-bootstrap-state.js +17 -0
- package/dist/src/lib/check-bootstrap-state.js.map +1 -0
- package/dist/src/lib/cliHelpCatalog.d.ts.map +1 -1
- package/dist/src/lib/cliHelpCatalog.js +12 -0
- package/dist/src/lib/cliHelpCatalog.js.map +1 -1
- package/dist/src/lib/test-copilot-bootstrap.d.ts +2 -0
- package/dist/src/lib/test-copilot-bootstrap.d.ts.map +1 -0
- package/dist/src/lib/test-copilot-bootstrap.js +139 -0
- package/dist/src/lib/test-copilot-bootstrap.js.map +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -3,906 +3,283 @@
|
|
|
3
3
|
[](https://www.gnu.org/licenses/agpl-3.0.en.html)
|
|
4
4
|
[](https://modelcontextprotocol.io)
|
|
5
5
|
[](https://www.npmjs.com/package/iranti)
|
|
6
|
-
[](https://www.typescriptlang.org/)
|
|
8
|
-
[](https://www.crewai.com/)
|
|
6
|
+
[](https://www.npmjs.com/package/iranti)
|
|
9
7
|
|
|
10
|
-
**
|
|
8
|
+
**Shared memory for AI coding tools — Claude Code, Codex CLI, and GitHub Copilot.**
|
|
11
9
|
|
|
12
|
-
Iranti gives
|
|
13
|
-
|
|
14
|
-
**Repo version:** `0.3.11`
|
|
15
|
-
Published packages:
|
|
16
|
-
- npm `iranti@0.3.11`
|
|
17
|
-
- npm `@iranti/sdk@0.3.11`
|
|
18
|
-
- PyPI `iranti==0.3.11`
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## What is Iranti?
|
|
23
|
-
|
|
24
|
-
Iranti is a knowledge base for multi-agent systems. The primary read path is identity retrieval — this specific entity (`project/nexus_prime`), this specific key (`deadline`), with confidence attached. When Agent A writes a fact, Agent B can retrieve it by exact lookup without being told it exists. Facts persist in PostgreSQL and survive context window boundaries through the `observe()` API. For discovery workflows, Iranti supports hybrid search (full-text + vector similarity).
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## MCP Server
|
|
29
|
-
|
|
30
|
-
Iranti ships a stdio MCP server compatible with Claude Code, GitHub Copilot, Codex, and any MCP-compliant client:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
# Fast path for Claude Code
|
|
34
|
-
iranti claude-setup
|
|
35
|
-
|
|
36
|
-
# Fast path for Codex
|
|
37
|
-
iranti codex-setup
|
|
38
|
-
|
|
39
|
-
# Fast path for GitHub Copilot
|
|
40
|
-
iranti copilot-setup
|
|
41
|
-
|
|
42
|
-
# Manual / other MCP clients
|
|
43
|
-
iranti mcp
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
MCP tools exposed: `iranti_handshake`, `iranti_attend`, `iranti_write`, `iranti_query`, `iranti_search`, `iranti_checkpoint`, `iranti_ingest`, `iranti_relate`, `iranti_related`, `iranti_related_deep`, `iranti_history`, `iranti_who_knows`, `iranti_observe`, and more.
|
|
47
|
-
|
|
48
|
-
Full setup guides:
|
|
49
|
-
- [Claude Code](docs/guides/claude-code.md)
|
|
50
|
-
- [Codex](docs/guides/codex.md)
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Runtime Roles
|
|
55
|
-
|
|
56
|
-
- **User**: Person who interacts with an app or chatbot built on Iranti.
|
|
57
|
-
- **Agent**: External AI worker that writes/reads facts through Iranti APIs.
|
|
58
|
-
- **Attendant**: Per-agent memory manager that decides what to inject for each turn.
|
|
59
|
-
- **Librarian**: Conflict-aware writer that owns all KB writes.
|
|
60
|
-
- **Library**: Active truth store (`knowledge_base`) in PostgreSQL.
|
|
61
|
-
- **Archive**: Historical/superseded truth store (`archive`) in PostgreSQL.
|
|
62
|
-
- **Archivist**: Maintenance worker that archives stale/low-confidence facts and processes resolved escalations.
|
|
63
|
-
- **Resolutionist**: Interactive CLI reviewer that guides humans through pending escalation files and writes valid authoritative resolutions.
|
|
10
|
+
Iranti is a self-hosted MCP server that gives your AI tools persistent, identity-based memory. Facts written in one session are retrievable in any other — across tools, projects, and context resets.
|
|
64
11
|
|
|
65
12
|
---
|
|
66
13
|
|
|
67
|
-
##
|
|
68
|
-
|
|
69
|
-
| Feature | Vector DB | Iranti |
|
|
70
|
-
|---|---|---|
|
|
71
|
-
| **Retrieval** | Similarity (nearest neighbor) | Identity-first + optional hybrid search |
|
|
72
|
-
| **Storage** | Embeddings in vector space | Structured facts with keys |
|
|
73
|
-
| **Persistence** | Stateless between calls | Persistent across sessions |
|
|
74
|
-
| **Confidence** | No confidence tracking | Per-fact confidence scores |
|
|
75
|
-
| **Conflicts** | No conflict resolution | Automatic resolution + escalation |
|
|
76
|
-
| **Context** | No context awareness | `observe()` injects missing facts |
|
|
77
|
-
|
|
78
|
-
Vector databases answer "what's similar to X?" Iranti answers "what do we know about X?" and can run hybrid search when exact keys are unknown.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Benchmark Summary
|
|
83
|
-
|
|
84
|
-
Iranti now has current rerun evidence across exact retrieval, process continuity, upgrade durability, relationships, bounded conflict handling, and bounded recovery behavior. The current picture is stronger and narrower than the early validation story: exact, durable, shared memory is validated; broad semantic-memory and autonomous-recovery claims still need explicit limits.
|
|
85
|
-
|
|
86
|
-
### Confirmed Strengths
|
|
87
|
-
|
|
88
|
-
- **Exact lookup (`iranti_query`)**: The prepublish candidate for the current `0.3.0` line still scored `10/10` on the canonical B1 exact-retrieval arm.
|
|
89
|
-
- **Persistence across sessions and processes**: Facts survive context-window loss and genuine process boundaries, with current reruns and validation passes covering process-isolated reads plus cross-process invalidation.
|
|
90
|
-
- **Upgrade durability**: A fresh continuity chain now passes across public npm `0.2.49 -> 0.2.50 -> 0.2.51` plus a final prepublish candidate hop on the `0.3.0` line.
|
|
91
|
-
- **Conflict handling**: Reliable when confidence differentials are large and explicit.
|
|
92
|
-
- **Relationship traversal and multi-agent coordination**: Relationship writes plus one-hop/deep traversal work, and agents can share memory across genuine subprocess boundaries with zero shared conversational context.
|
|
93
|
-
- **Provenance on writes**: Write-side attribution through stored source metadata is working and benchmark-confirmed.
|
|
94
|
-
- **Ingest**: Prose extraction is accurate on clean entities in the bounded rerun surfaces already documented.
|
|
95
|
-
- **Observe with hints / explicit recovery**: `iranti_observe` with hints and explicit query-based recovery are meaningfully useful today.
|
|
96
|
-
- **Protocol enforcement turn-gate**: Strict turn-cycle enforcement (handshake → attend → discover → post-response) is validated by focused route and MCP regression tests. In `strict` mode, KB discovery routes return HTTP 428 with a structured violation payload before an agent that skipped attend can silently read stale memory. Injected facts now include a `lastUpdated` timestamp so the calling agent can judge freshness at the point of injection.
|
|
97
|
-
|
|
98
|
-
Recent fixes since the last rerun:
|
|
99
|
-
- **Search now bridges semantic hits across relationships for filtered retrieval.** A strong incident or issue hit can now propagate back onto the owning filtered entity over up to two hops, so filtered project search no longer depends on direct lexical overlap alone.
|
|
100
|
-
- **`iranti_attend` now safe-defaults parse failures toward memory on non-greeting turns.** Terse prompts such as `help`, `why?`, or `how?` no longer silently fall through to `classification_parse_failed_default_false`.
|
|
101
|
-
- **Hybrid search now indexes entity addresses directly.** Addressed queries such as `project/<id> status` no longer rely on value-summary overlap alone.
|
|
102
|
-
|
|
103
|
-
### Current Limits
|
|
104
|
-
|
|
105
|
-
- **Upgrade durability is now test-covered.** The `v0.2.21` upgrade reinitialized the instance under test — a one-time operator incident, not a systemic design flaw. All Prisma migrations are additive (no DROP or TRUNCATE); Staff Namespace seeding is guarded by `isSeeded()`; `seed-codebase.ts` upserts to `codebase/*` entities only. A KB preservation test in `tests/runtime-lifecycle/run_setup_upgrade_tests.ts` now confirms user KB data written before a `setup` re-run survives intact.
|
|
106
|
-
- **Project learning is now only a bounded bind-time snapshot.** When you bind a project, Iranti derives a stable `IRANTI_CODEBASE_ENTITY` and writes a small snapshot from authoritative files such as `package.json`, `README.md`, `tsconfig.json`, `pyproject.toml`, `prisma/schema.prisma`, and common source directories. It does not yet crawl the repo continuously or build autonomous whole-project understanding.
|
|
107
|
-
- **Relationship and provenance reflection surfaces remain partially permission-gated in benchmark sessions.** The rerun did not prove `iranti_relate`, `iranti_related`, `iranti_related_deep`, or `iranti_who_knows` end-to-end under the benchmark session policy.
|
|
108
|
-
|
|
109
|
-
### Practical Position
|
|
110
|
-
|
|
111
|
-
Iranti is strongest today as **structured memory infrastructure for multi-agent systems**:
|
|
112
|
-
- exact entity/key lookup
|
|
113
|
-
- durable shared memory
|
|
114
|
-
- provenance-aware writes with source attribution and freshness timestamps
|
|
115
|
-
- conflict-aware storage
|
|
116
|
-
- session-aware recovery
|
|
117
|
-
- protocol-enforced turn discipline for trustworthy injection (opt-in strict mode)
|
|
118
|
-
|
|
119
|
-
It should not yet be described as a fully general semantic-memory, semantic-search, or autonomous-memory-injection system.
|
|
120
|
-
|
|
121
|
-
Historical benchmark material remains available here:
|
|
122
|
-
- [`docs/internal/validation_results.md`](docs/internal/validation_results.md)
|
|
123
|
-
- [`docs/internal/MULTI_FRAMEWORK_VALIDATION.md`](docs/internal/MULTI_FRAMEWORK_VALIDATION.md)
|
|
124
|
-
- [`docs/internal/conflict_benchmark.md`](docs/internal/conflict_benchmark.md)
|
|
125
|
-
- [`docs/internal/consistency_model.md`](docs/internal/consistency_model.md)
|
|
126
|
-
|
|
127
|
-
## Gap Analysis
|
|
128
|
-
|
|
129
|
-
Iranti targets a specific gap in the agent infrastructure stack: most competing systems give you semantic retrieval, framework-specific memory, or raw vector storage, but not the same combination of structured fact storage, cross-agent sharing, identity-based lookup, explicit confidence, and developer-visible conflict handling in one self-hostable package.
|
|
130
|
-
|
|
131
|
-
The current competitive case for Iranti is strongest when a team needs memory that behaves more like shared infrastructure than a chat transcript: facts are attached to entities, retrieved deterministically by `entityType/entityId + key`, versioned over time, and made available across agents without framework lock-in.
|
|
132
|
-
|
|
133
|
-
### Where Iranti Is Differentiated
|
|
134
|
-
|
|
135
|
-
- Identity-first fact retrieval through `entityType/entityId + key`
|
|
136
|
-
- Cross-agent fact sharing as a first-class model
|
|
137
|
-
- Conflict-aware writes through the Librarian
|
|
138
|
-
- Explicit per-fact confidence scores
|
|
139
|
-
- Per-agent memory injection through the Attendant
|
|
140
|
-
- Temporal exact lookup with `asOf` and ordered `history()`
|
|
141
|
-
- Relationship primitives through `relate()`, `getRelated()`, and `getRelatedDeep()` at the product surface, with benchmark confirmation for those MCP-accessible paths still pending
|
|
142
|
-
- Hybrid retrieval when exact keys are unknown
|
|
143
|
-
- Local install + project binding flow for Claude Code and Codex
|
|
144
|
-
- Published npm / PyPI surfaces with machine-level CLI setup
|
|
145
|
-
|
|
146
|
-
### Why That Gap Exists
|
|
147
|
-
|
|
148
|
-
The current landscape splits into three buckets:
|
|
149
|
-
|
|
150
|
-
1. **Memory libraries**
|
|
151
|
-
- Systems like Mem0, Zep, Letta, and framework-native memory layers solve parts of the problem.
|
|
152
|
-
- They usually optimize for semantic retrieval, agent-local memory, or framework integration.
|
|
153
|
-
- They rarely expose deterministic `entity + key` lookup, explicit confidence surfaces, and developer-controlled conflict handling together.
|
|
154
|
-
|
|
155
|
-
2. **Vector databases**
|
|
156
|
-
- Pinecone, Weaviate, Qdrant, Chroma, Milvus, LanceDB, and `pgvector` solve storage and retrieval infrastructure.
|
|
157
|
-
- They do not, by themselves, solve memory semantics such as conflict resolution, context injection, fact lifecycle, or shared agent-facing state.
|
|
158
|
-
|
|
159
|
-
3. **Multi-agent frameworks**
|
|
160
|
-
- CrewAI, LangGraph, AutoGen, CAMEL, MetaGPT, and similar frameworks often include some memory support.
|
|
161
|
-
- In practice, that memory is usually framework-coupled, shallow on conflict semantics, and difficult to reuse outside the framework that created it.
|
|
162
|
-
|
|
163
|
-
### Main Gaps
|
|
164
|
-
|
|
165
|
-
1. **Operational maturity**
|
|
166
|
-
- Local PostgreSQL setup is still a real source of friction.
|
|
167
|
-
- The product needs stronger diagnostics, connection recovery, and less dependence on users debugging local database state by hand.
|
|
168
|
-
|
|
169
|
-
2. **Onboarding still has sharp edges**
|
|
170
|
-
- `iranti setup` is materially better than before, but first-run still assumes too much infrastructure literacy.
|
|
171
|
-
- Managed Postgres paths, cleaner bootstrap verification, and fewer environment-level surprises are still needed.
|
|
172
|
-
|
|
173
|
-
3. **No operator UI yet**
|
|
174
|
-
- Iranti is still CLI-first.
|
|
175
|
-
- There is no control plane yet for provider keys, project bindings, integrations, memory inspection, and escalation review.
|
|
176
|
-
|
|
177
|
-
4. **Adoption proof is still early**
|
|
178
|
-
- The repo has validation experiments and real local end-to-end usage, but broad production adoption is still limited.
|
|
179
|
-
- The next product truth has to come from external users and real workloads, not more speculative architecture alone.
|
|
180
|
-
|
|
181
|
-
5. **Hosted product is not built**
|
|
182
|
-
- Open-source/local infrastructure is the active surface today.
|
|
183
|
-
- Hosted deployment, multi-tenant operations, billing, and cloud onboarding remain future work.
|
|
184
|
-
|
|
185
|
-
6. **Graph-native reasoning is still limited**
|
|
186
|
-
- Iranti supports explicit entity relationships today.
|
|
187
|
-
- It does not yet compete with graph-first systems on temporal graph traversal or graph-native reasoning depth.
|
|
188
|
-
|
|
189
|
-
7. **Memory extraction is not the main model**
|
|
190
|
-
- Iranti supports structured writes and ingest/chunking, but it is not primarily a "dump arbitrary conversations in and auto-magically derive perfect memory" system.
|
|
191
|
-
- That is a deliberate tradeoff in favor of explicit, inspectable facts, but it increases integration work.
|
|
192
|
-
|
|
193
|
-
### Current Position
|
|
194
|
-
|
|
195
|
-
Iranti is strongest today as infrastructure for developers building multi-agent systems who need shared, structured, queryable memory rather than pure semantic recall. The current benchmark base now supports a more concrete product claim:
|
|
196
|
-
|
|
197
|
-
- exact cross-agent fact transfer works at meaningful context scales
|
|
198
|
-
- facts survive session loss and genuine process breaks
|
|
199
|
-
- same-key conflicting writes are serialized and observable
|
|
200
|
-
- prose ingest is accurate on clean entities
|
|
201
|
-
- attended recovery works with explicit hints, while autonomous attend classification remains a known defect
|
|
202
|
-
|
|
203
|
-
That is still not a claim that multi-agent memory is solved. It is a claim that Iranti now has broader evidence for durable, structured, attribution-aware memory with exact retrieval and bounded recovery behavior.
|
|
204
|
-
|
|
205
|
-
The next leverage is still product simplicity: setup, operations, and day-to-day inspection need to be simple enough that real users keep Iranti in the loop.
|
|
206
|
-
|
|
207
|
-
## Quickstart
|
|
208
|
-
|
|
209
|
-
**Requirements**: Node.js 18+, PostgreSQL with pgvector support, Python 3.8+
|
|
210
|
-
|
|
211
|
-
Docker is optional. It is one local way to run PostgreSQL if you do not already have a database. Iranti still requires PostgreSQL; the setup improvement is smarter bootstrap and clearer guidance, not a second storage backend.
|
|
14
|
+
## Quick Start
|
|
212
15
|
|
|
213
16
|
```bash
|
|
214
|
-
#
|
|
17
|
+
# Install globally
|
|
215
18
|
npm install -g iranti
|
|
216
19
|
|
|
217
|
-
#
|
|
20
|
+
# Run the guided setup (configures database, API key, project binding)
|
|
218
21
|
iranti setup
|
|
219
22
|
|
|
220
|
-
#
|
|
23
|
+
# Start the instance
|
|
221
24
|
iranti run --instance local
|
|
222
25
|
```
|
|
223
26
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
If local PostgreSQL is available and pgvector-capable, setup can bootstrap a localhost database for you. If Docker is available, setup now prefers the Docker path over a plain local listener because it guarantees pgvector. If local PostgreSQL is reachable but does not provide pgvector, setup now fails early with a direct action path instead of a late Prisma migration error.
|
|
227
|
-
|
|
228
|
-
Long-running agents can now checkpoint and recover interrupted work. Programmatic session lifecycle methods are available through the SDK and REST API:
|
|
229
|
-
- `checkpoint()`
|
|
230
|
-
- `inspectSession()`
|
|
231
|
-
- `listSessions()`
|
|
232
|
-
- `resumeSession()`
|
|
233
|
-
- `completeSession()`
|
|
234
|
-
- `abandonSession()`
|
|
235
|
-
|
|
236
|
-
Running instances now publish runtime metadata in `/health`, and the CLI can see that state through `iranti status`, `iranti instance show`, and `iranti upgrade --check`. When you want an installed upgrade to immediately take effect on an instance-backed API server, use:
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
iranti upgrade --restart --instance local
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
If something still fails and you need more detail, use:
|
|
243
|
-
|
|
244
|
-
```bash
|
|
245
|
-
iranti doctor --debug
|
|
246
|
-
iranti run --instance local --debug
|
|
247
|
-
iranti upgrade --verbose
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
If you want to remove Iranti cleanly:
|
|
27
|
+
Then wire it into your AI tool:
|
|
251
28
|
|
|
252
29
|
```bash
|
|
253
|
-
iranti
|
|
254
|
-
iranti
|
|
30
|
+
iranti claude-setup # Claude Code
|
|
31
|
+
iranti codex-setup # Codex CLI
|
|
32
|
+
iranti copilot-setup # GitHub Copilot
|
|
255
33
|
```
|
|
256
34
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
Advanced/manual path:
|
|
260
|
-
|
|
261
|
-
```bash
|
|
262
|
-
# 1. Clone and configure
|
|
263
|
-
git clone https://github.com/nfemmanuel/iranti
|
|
264
|
-
cd iranti
|
|
265
|
-
cp .env.example .env # Set DATABASE_URL and IRANTI_API_KEY
|
|
266
|
-
|
|
267
|
-
# Optional runtime hygiene
|
|
268
|
-
# IRANTI_ESCALATION_DIR=C:/Users/<you>/.iranti/escalation
|
|
269
|
-
# IRANTI_ARCHIVIST_WATCH=true
|
|
270
|
-
# IRANTI_ARCHIVIST_DEBOUNCE_MS=60000
|
|
271
|
-
# IRANTI_ARCHIVIST_INTERVAL_MS=21600000
|
|
272
|
-
|
|
273
|
-
# 2. Start PostgreSQL
|
|
274
|
-
docker-compose up -d
|
|
275
|
-
|
|
276
|
-
# 3. Install and initialize
|
|
277
|
-
npm install
|
|
278
|
-
npm run setup # Runs migrations
|
|
279
|
-
|
|
280
|
-
# 4. Start API server
|
|
281
|
-
npm run api # Runs on port 3001
|
|
282
|
-
|
|
283
|
-
# 5. Install Python client
|
|
284
|
-
pip install iranti
|
|
285
|
-
|
|
286
|
-
# Optional: install the TypeScript client
|
|
287
|
-
npm install @iranti/sdk
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Archivist Scheduling Knobs
|
|
291
|
-
|
|
292
|
-
- `IRANTI_ARCHIVIST_WATCH=true` enables file-change watching on escalation `active/`.
|
|
293
|
-
- `IRANTI_ARCHIVIST_DEBOUNCE_MS=60000` runs maintenance 60s after the latest file change.
|
|
294
|
-
- `IRANTI_ARCHIVIST_INTERVAL_MS=21600000` runs maintenance every 6 hours (set `0` to disable).
|
|
295
|
-
- `IRANTI_ESCALATION_DIR` sets escalation storage root. Default is `~/.iranti/escalation`, keeping escalation files out of the repo by default.
|
|
296
|
-
|
|
297
|
-
### Per-User API Keys (Recommended)
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
# Create a key for one user/app (prints token once)
|
|
301
|
-
npm run api-key:create -- --key-id chatbot_alice --owner "Alice chatbot" --scopes "kb:read,kb:write,memory:read,memory:write,agents:read,agents:write"
|
|
35
|
+
That's it. Your AI tool now has persistent memory across sessions.
|
|
302
36
|
|
|
303
|
-
|
|
304
|
-
npm run api-key:list
|
|
305
|
-
|
|
306
|
-
# Revoke a key
|
|
307
|
-
npm run api-key:revoke -- --key-id chatbot_alice
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
Use the printed token (`keyId.secret`) as `X-Iranti-Key`.
|
|
311
|
-
Scopes use `resource:action` format (for example `kb:read`, `memory:write`, `metrics:read`, `proxy:chat`).
|
|
312
|
-
|
|
313
|
-
### Security Baseline
|
|
314
|
-
|
|
315
|
-
- Use one scoped key per app/service identity.
|
|
316
|
-
- Rotate any key that is exposed in logs, screenshots, or chat.
|
|
317
|
-
- Keep escalation/log paths outside the repo working tree.
|
|
318
|
-
- Use TLS/reverse proxy for non-local deployments.
|
|
319
|
-
|
|
320
|
-
Security quickstart: [`docs/guides/security-quickstart.md`](docs/guides/security-quickstart.md)
|
|
321
|
-
Operator manual: [`docs/guides/manual.md`](docs/guides/manual.md)
|
|
322
|
-
Claude Code guide: [`docs/guides/claude-code.md`](docs/guides/claude-code.md)
|
|
323
|
-
Codex guide: [`docs/guides/codex.md`](docs/guides/codex.md)
|
|
324
|
-
Release guide: [`docs/guides/releasing.md`](docs/guides/releasing.md)
|
|
325
|
-
Vector backend guide: [`docs/guides/vector-backends.md`](docs/guides/vector-backends.md)
|
|
326
|
-
|
|
327
|
-
### Claude Code via MCP
|
|
328
|
-
|
|
329
|
-
Iranti ships a local stdio MCP server for Claude Code and other MCP clients:
|
|
330
|
-
|
|
331
|
-
```bash
|
|
332
|
-
iranti mcp
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
Use it with a project-local `.mcp.json`, and optionally add `iranti claude-hook` for `SessionStart` and `UserPromptSubmit`.
|
|
37
|
+
---
|
|
336
38
|
|
|
337
|
-
|
|
39
|
+
## Supported Tools
|
|
338
40
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
41
|
+
| Tool | Command | What it does |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| **Claude Code** | `iranti claude-setup` | Adds `.mcp.json`, `CLAUDE.md`, and session hooks |
|
|
44
|
+
| **Codex CLI** | `iranti codex-setup` | Registers Iranti in the global MCP registry |
|
|
45
|
+
| **GitHub Copilot** | `iranti copilot-setup` | Writes MCP config to `.mcp.json` + `.vscode/mcp.json`, protocol instructions to `.github/copilot-instructions.md` |
|
|
46
|
+
| **Any MCP client** | `iranti mcp` | Runs the stdio MCP server directly |
|
|
342
47
|
|
|
343
|
-
|
|
48
|
+
---
|
|
344
49
|
|
|
345
|
-
|
|
50
|
+
## What It Does
|
|
346
51
|
|
|
347
|
-
|
|
52
|
+
Iranti stores facts as `entityType/entityId → key → value` triples in PostgreSQL. Any agent that knows the entity and key can retrieve the fact exactly — no semantic guessing, no hallucinated state.
|
|
348
53
|
|
|
349
|
-
```bash
|
|
350
|
-
iranti codex-setup
|
|
351
|
-
codex -C /path/to/your/project
|
|
352
54
|
```
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
Alias:
|
|
357
|
-
|
|
358
|
-
```bash
|
|
359
|
-
iranti integrate codex
|
|
55
|
+
Agent A writes: project/my-app → deployment_status → "deployed to staging"
|
|
56
|
+
Agent B reads: project/my-app → deployment_status → "deployed to staging" ✓
|
|
360
57
|
```
|
|
361
58
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
### Resolve Pending Escalations
|
|
365
|
-
|
|
366
|
-
Review unresolved human-escalation files from the CLI:
|
|
367
|
-
|
|
368
|
-
```bash
|
|
369
|
-
iranti resolve
|
|
370
|
-
```
|
|
59
|
+
Facts persist across sessions, context resets, and tool switches. When you restart Claude Code tomorrow, it can pick up exactly where you left off.
|
|
371
60
|
|
|
372
|
-
|
|
61
|
+
### Key capabilities
|
|
373
62
|
|
|
374
|
-
|
|
63
|
+
- **Exact lookup** — retrieve by `entityType/entityId + key`, deterministic and fast
|
|
64
|
+
- **Hybrid search** — lexical + vector similarity when exact keys are unknown
|
|
65
|
+
- **Cross-tool sharing** — Claude Code, Codex, and Copilot share the same memory
|
|
66
|
+
- **Conflict resolution** — concurrent writes from multiple agents are detected and resolved
|
|
67
|
+
- **Per-fact confidence** — every fact carries a confidence score; low-confidence facts age out
|
|
68
|
+
- **Session recovery** — checkpoint/resume for interrupted work
|
|
69
|
+
- **User operating rules** — define trigger-based rules that surface only when relevant
|
|
70
|
+
- **File-change recall** — agents remember which files changed and why
|
|
375
71
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
```bash
|
|
379
|
-
iranti chat
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
Use `--agent`, `--provider`, and `--model` to pin the session identity and model routing.
|
|
383
|
-
The chat surface now includes slash commands for fact history, relationships, conflict-resolution handoff, and confidence updates in addition to memory search/write operations.
|
|
384
|
-
Guide: [`docs/guides/chat.md`](docs/guides/chat.md)
|
|
385
|
-
|
|
386
|
-
### Manual Attendant Inspection
|
|
72
|
+
---
|
|
387
73
|
|
|
388
|
-
|
|
74
|
+
## MCP Tools
|
|
389
75
|
|
|
390
|
-
|
|
391
|
-
iranti handshake --task "Working on ProofScript repo"
|
|
392
|
-
iranti attend "What did we decide about the parser?" --context-file transcript.txt
|
|
393
|
-
```
|
|
76
|
+
When connected via MCP, Iranti exposes these tools to your AI tool:
|
|
394
77
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
78
|
+
| Tool | Purpose |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `iranti_handshake` | Initialize session, load operating rules and working memory |
|
|
81
|
+
| `iranti_attend` | Pre/post-response memory injection — call before every reply |
|
|
82
|
+
| `iranti_write` | Write a durable fact to shared memory |
|
|
83
|
+
| `iranti_query` | Exact entity+key lookup |
|
|
84
|
+
| `iranti_search` | Hybrid semantic/lexical search |
|
|
85
|
+
| `iranti_checkpoint` | Save current task progress |
|
|
86
|
+
| `iranti_ingest` | Extract facts from prose or documents |
|
|
87
|
+
| `iranti_relate` | Create a relationship between two entities |
|
|
88
|
+
| `iranti_related` / `iranti_related_deep` | Traverse entity relationships |
|
|
89
|
+
| `iranti_history` | Fact history with timestamps |
|
|
90
|
+
| `iranti_who_knows` | Find which agents have written about an entity |
|
|
91
|
+
| `iranti_observe` | Demand-driven context injection with entity hints |
|
|
92
|
+
| `iranti_write_rule` | Write a user operating rule with trigger conditions |
|
|
93
|
+
| `iranti_remember_response` | Auto-persist facts from an assistant response |
|
|
398
94
|
|
|
399
95
|
---
|
|
400
96
|
|
|
401
|
-
## Install Strategy
|
|
402
|
-
|
|
403
|
-
Iranti now supports a two-layer install flow:
|
|
97
|
+
## Install Strategy
|
|
404
98
|
|
|
405
|
-
|
|
406
|
-
2. **Project layer**: each chatbot/app binds to one instance with a local `.env.iranti`.
|
|
99
|
+
Iranti uses a two-layer model: one machine-level runtime, many project bindings.
|
|
407
100
|
|
|
408
|
-
### 1
|
|
101
|
+
### 1. Install and set up
|
|
409
102
|
|
|
410
103
|
```bash
|
|
411
|
-
# If published package is available
|
|
412
104
|
npm install -g iranti
|
|
413
|
-
|
|
414
|
-
# Or from this repo (local simulation)
|
|
415
|
-
npm install -g .
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
### 2) Initialize machine runtime root
|
|
419
|
-
|
|
420
|
-
```bash
|
|
421
105
|
iranti setup
|
|
422
|
-
|
|
423
|
-
# non-interactive automation
|
|
424
|
-
iranti setup --defaults --db-url "postgresql://postgres:realpassword@localhost:5432/iranti_local"
|
|
425
|
-
iranti setup --config ./iranti.setup.json
|
|
426
|
-
|
|
427
|
-
# or, if you want the lower-level manual path:
|
|
428
|
-
iranti install --scope user
|
|
429
106
|
```
|
|
430
107
|
|
|
431
|
-
`iranti setup`
|
|
432
|
-
-
|
|
433
|
-
-
|
|
434
|
-
-
|
|
435
|
-
- database onboarding:
|
|
436
|
-
- existing Postgres
|
|
437
|
-
- managed Postgres
|
|
438
|
-
- optional Docker-hosted Postgres for local development
|
|
439
|
-
- provider API keys
|
|
440
|
-
- Iranti client API key generation
|
|
441
|
-
- one or more project bindings
|
|
442
|
-
- optional Claude Code / Codex integration scaffolding
|
|
443
|
-
|
|
444
|
-
Operator-facing CLI help now includes short "what it does" and "use this when" guidance, so `iranti <command> --help` is the quickest way to choose the right entry point.
|
|
445
|
-
|
|
446
|
-
For automation:
|
|
447
|
-
- `iranti setup --defaults` uses sensible defaults plus environment/flag input, but still requires a real `DATABASE_URL`.
|
|
448
|
-
- `iranti setup --config <file>` reads a JSON setup plan for repeatable bootstrap.
|
|
449
|
-
- `--bootstrap-db` runs migrations and seeding during automated setup when the database is reachable.
|
|
450
|
-
- Example config: [docs/guides/iranti.setup.example.json](docs/guides/iranti.setup.example.json)
|
|
451
|
-
|
|
452
|
-
Default API port remains `3001`. The setup wizard now warns when that port is already in use and suggests the next free port instead of forcing users to debug the collision manually.
|
|
453
|
-
|
|
454
|
-
Defaults:
|
|
455
|
-
- Windows user scope: `%USERPROFILE%\\.iranti`
|
|
456
|
-
- Windows system scope: `%ProgramData%\\Iranti`
|
|
457
|
-
- Linux system scope: `/var/lib/iranti`
|
|
458
|
-
- macOS system scope: `/Library/Application Support/Iranti`
|
|
459
|
-
|
|
460
|
-
### 3) Create a named instance
|
|
461
|
-
|
|
462
|
-
```bash
|
|
463
|
-
iranti instance create local --port 3001 --db-url "postgresql://postgres:yourpassword@localhost:5432/iranti_local" --provider mock
|
|
464
|
-
iranti instance show local
|
|
465
|
-
```
|
|
108
|
+
`iranti setup` walks you through:
|
|
109
|
+
- Instance creation and database onboarding (local Postgres, managed Postgres, or Docker)
|
|
110
|
+
- LLM provider API keys (OpenAI, Claude, Gemini, Groq, Mistral, or local Ollama)
|
|
111
|
+
- Project binding
|
|
466
112
|
|
|
467
|
-
|
|
113
|
+
Non-interactive automation:
|
|
468
114
|
|
|
469
115
|
```bash
|
|
470
|
-
|
|
471
|
-
iranti configure instance local --provider openai --provider-key replace-with-real-openai-key --db-url "postgresql://postgres:realpassword@localhost:5432/iranti_local"
|
|
472
|
-
iranti configure instance local --interactive
|
|
473
|
-
|
|
474
|
-
# Provider key shortcuts
|
|
475
|
-
iranti list api-keys --instance local
|
|
476
|
-
iranti add api-key openai --instance local
|
|
477
|
-
iranti update api-key claude --instance local
|
|
478
|
-
iranti remove api-key gemini --instance local
|
|
479
|
-
|
|
480
|
-
# Create a registry-backed API key and sync it into the instance env
|
|
481
|
-
iranti auth create-key --instance local --key-id local_admin --owner "Local Admin" --scopes "kb:read,kb:write,memory:read,memory:write,agents:read,agents:write" --write-instance
|
|
116
|
+
iranti setup --defaults --db-url "postgresql://postgres:yourpassword@localhost:5432/iranti"
|
|
482
117
|
```
|
|
483
118
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
### 4) Run Iranti from that instance
|
|
119
|
+
### 2. Start the instance
|
|
487
120
|
|
|
488
121
|
```bash
|
|
489
122
|
iranti run --instance local
|
|
490
123
|
```
|
|
491
124
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
### 5) Bind any chatbot/app project to that instance
|
|
125
|
+
### 3. Bind a project
|
|
495
126
|
|
|
496
127
|
```bash
|
|
497
|
-
cd /path/to/your/
|
|
498
|
-
iranti project init . --instance local --agent-id
|
|
128
|
+
cd /path/to/your/project
|
|
129
|
+
iranti project init . --instance local --agent-id my_agent
|
|
499
130
|
```
|
|
500
131
|
|
|
501
|
-
This writes `.env.iranti`
|
|
502
|
-
It also writes a derived `IRANTI_CODEBASE_ENTITY` and a bounded initial project snapshot for that bound repo.
|
|
132
|
+
This writes `.env.iranti` with `IRANTI_URL`, `IRANTI_API_KEY`, and agent identity. Each agent in a multi-agent system gets its own `--agent-id`.
|
|
503
133
|
|
|
504
|
-
|
|
134
|
+
### 4. Integrate with your AI tool
|
|
505
135
|
|
|
506
136
|
```bash
|
|
507
|
-
iranti
|
|
508
|
-
iranti configure project . --interactive
|
|
509
|
-
iranti project unbind .
|
|
510
|
-
iranti auth create-key --instance local --key-id chatbot_worker --owner "Chatbot Worker" --scopes "kb:read,memory:read,memory:write" --project .
|
|
137
|
+
iranti claude-setup # or codex-setup / copilot-setup
|
|
511
138
|
```
|
|
512
139
|
|
|
513
|
-
For multi-agent systems, bind once per project and set unique agent IDs per worker (for example `planner_agent`, `research_agent`, `critic_agent`).
|
|
514
|
-
|
|
515
|
-
### Installation Diagnostics
|
|
516
|
-
|
|
517
|
-
Use the CLI doctor command before first run or before a release check:
|
|
518
|
-
|
|
519
|
-
```bash
|
|
520
|
-
iranti doctor
|
|
521
|
-
iranti doctor --instance local
|
|
522
|
-
iranti status
|
|
523
|
-
iranti upgrade --check
|
|
524
|
-
iranti upgrade --dry-run
|
|
525
|
-
iranti upgrade --yes
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
This validates the active env file, database URL, API key presence, provider selection, and provider-specific credentials.
|
|
529
|
-
`iranti status` shows the current runtime root, known instances, and local binding files.
|
|
530
|
-
`iranti upgrade` detects repo/global/Python install paths, compares current vs latest published versions, prints the exact plan, and executes the selected upgrade path when you pass `--yes`.
|
|
531
|
-
On Windows, if the currently running CLI is itself the global npm install being upgraded, Iranti now hands that npm-global step off to a detached updater process instead of trying to replace the live binary in place.
|
|
532
|
-
`iranti configure ...` updates instance/project credentials without manual env editing.
|
|
533
|
-
`iranti auth ...` manages registry-backed API keys and can sync them into instance or project bindings.
|
|
534
|
-
When you pass `--root` in Windows `cmd.exe`, use no quotes or double quotes. Single quotes are treated literally there.
|
|
535
|
-
|
|
536
140
|
---
|
|
537
141
|
|
|
538
|
-
##
|
|
539
|
-
|
|
540
|
-
### Write a Fact
|
|
541
|
-
|
|
542
|
-
```python
|
|
543
|
-
from clients.python.iranti import IrantiClient
|
|
544
|
-
|
|
545
|
-
client = IrantiClient(
|
|
546
|
-
base_url="http://localhost:3001",
|
|
547
|
-
api_key="your_api_key_here"
|
|
548
|
-
)
|
|
142
|
+
## API Keys
|
|
549
143
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
summary="Affiliated with MIT CSAIL", # Compressed for working memory
|
|
555
|
-
confidence=85, # 0-100
|
|
556
|
-
source="OpenAlex",
|
|
557
|
-
agent="research_agent_001"
|
|
558
|
-
)
|
|
559
|
-
|
|
560
|
-
print(result.action) # 'created', 'updated', 'escalated', or 'rejected'
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
### Query a Fact
|
|
564
|
-
|
|
565
|
-
```python
|
|
566
|
-
result = client.query("researcher/jane_smith", "affiliation")
|
|
567
|
-
|
|
568
|
-
if result.found:
|
|
569
|
-
print(result.value) # {"institution": "MIT", "department": "CSAIL"}
|
|
570
|
-
print(result.confidence) # 85
|
|
571
|
-
print(result.source) # "OpenAlex"
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
### Query All Facts for an Entity
|
|
575
|
-
|
|
576
|
-
```python
|
|
577
|
-
facts = client.query_all("researcher/jane_smith")
|
|
578
|
-
|
|
579
|
-
for fact in facts:
|
|
580
|
-
print(f"[{fact['key']}] {fact['summary']} (confidence: {fact['confidence']})")
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
### Graph Traversal
|
|
584
|
-
|
|
585
|
-
```python
|
|
586
|
-
from clients.python.iranti import IrantiClient
|
|
587
|
-
|
|
588
|
-
client = IrantiClient(base_url="http://localhost:3001", api_key="your_api_key_here")
|
|
589
|
-
|
|
590
|
-
# Agent 1 writes facts and links them into a graph.
|
|
591
|
-
client.write("researcher/jane_smith", "affiliation", {"lab": "CSAIL"}, "Jane Smith is affiliated with CSAIL", 90, "OpenAlex", "research_agent")
|
|
592
|
-
client.write("project/quantum_bridge", "status", {"phase": "active"}, "Quantum Bridge is active", 88, "project_brief", "research_agent")
|
|
593
|
-
|
|
594
|
-
client.relate("researcher/jane_smith", "MEMBER_OF", "lab/csail", created_by="research_agent")
|
|
595
|
-
client.relate("lab/csail", "LEADS", "project/quantum_bridge", created_by="research_agent")
|
|
596
|
-
|
|
597
|
-
# Agent 2 starts cold and traverses outward from Jane Smith.
|
|
598
|
-
one_hop = client.related("researcher/jane_smith")
|
|
599
|
-
labs = [f"{r['toType']}/{r['toId']}" for r in one_hop if r["relationshipType"] == "MEMBER_OF"]
|
|
144
|
+
```bash
|
|
145
|
+
# Create a scoped key for one user or service
|
|
146
|
+
iranti auth create-key --instance local --key-id my_app --owner "My App" \
|
|
147
|
+
--scopes "kb:read,kb:write,memory:read,memory:write"
|
|
600
148
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
for rel in client.related(lab):
|
|
604
|
-
if rel["relationshipType"] == "LEADS":
|
|
605
|
-
project = f"{rel['toType']}/{rel['toId']}"
|
|
606
|
-
status = client.query(project, "status")
|
|
607
|
-
projects.append((project, status.value["phase"]))
|
|
149
|
+
# List keys
|
|
150
|
+
iranti list api-keys --instance local
|
|
608
151
|
|
|
609
|
-
|
|
610
|
-
|
|
152
|
+
# Revoke a key
|
|
153
|
+
iranti auth revoke-key --instance local --key-id my_app
|
|
611
154
|
```
|
|
612
155
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
Relationship types are caller-defined strings. Common conventions:
|
|
616
|
-
|
|
617
|
-
| Relationship Type | Meaning |
|
|
618
|
-
|---|---|
|
|
619
|
-
| `MEMBER_OF` | Entity belongs to a team, lab, org, or group |
|
|
620
|
-
| `PART_OF` | Entity is a component or sub-unit of another entity |
|
|
621
|
-
| `AUTHORED` | Person or agent created a document, paper, or artifact |
|
|
622
|
-
| `LEADS` | Person, team, or org leads a project or effort |
|
|
623
|
-
| `DEPENDS_ON` | Project, service, or task depends on another entity |
|
|
624
|
-
| `REPORTS_TO` | Directed reporting relationship between people or agents |
|
|
156
|
+
---
|
|
625
157
|
|
|
626
|
-
|
|
158
|
+
## SDK Usage
|
|
627
159
|
|
|
628
|
-
|
|
160
|
+
**Python** ([PyPI](https://pypi.org/project/iranti/)):
|
|
629
161
|
|
|
630
162
|
```python
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
163
|
+
from iranti import IrantiClient
|
|
164
|
+
|
|
165
|
+
client = IrantiClient(base_url="http://localhost:3001", api_key="your_key")
|
|
166
|
+
|
|
167
|
+
# Write a fact
|
|
168
|
+
client.write(
|
|
169
|
+
entity="project/my-app",
|
|
170
|
+
key="status",
|
|
171
|
+
value="in_review",
|
|
172
|
+
summary="App is in review",
|
|
173
|
+
confidence=90,
|
|
174
|
+
source="my_script",
|
|
175
|
+
agent="my_agent",
|
|
637
176
|
)
|
|
638
177
|
|
|
639
|
-
|
|
640
|
-
|
|
178
|
+
# Read it back
|
|
179
|
+
fact = client.query(entity="project/my-app", key="status")
|
|
641
180
|
```
|
|
642
181
|
|
|
643
|
-
|
|
182
|
+
**TypeScript** ([npm](https://www.npmjs.com/package/@iranti/sdk)):
|
|
644
183
|
|
|
645
|
-
|
|
184
|
+
```typescript
|
|
185
|
+
import { IrantiClient } from "@iranti/sdk";
|
|
646
186
|
|
|
647
|
-
|
|
648
|
-
# Before each LLM call, let Attendant decide if memory is needed
|
|
649
|
-
result = client.attend(
|
|
650
|
-
agent_id="research_agent_001",
|
|
651
|
-
latest_message="What's Jane Smith's current affiliation?",
|
|
652
|
-
current_context="User: What's Jane Smith's current affiliation?\nAssistant: Let me check...",
|
|
653
|
-
max_facts=5,
|
|
654
|
-
phase="pre-response"
|
|
655
|
-
)
|
|
187
|
+
const client = new IrantiClient({ baseUrl: "http://localhost:3001", apiKey: "your_key" });
|
|
656
188
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
189
|
+
await client.write({
|
|
190
|
+
entity: "project/my-app",
|
|
191
|
+
key: "status",
|
|
192
|
+
value: "in_review",
|
|
193
|
+
summary: "App is in review",
|
|
194
|
+
confidence: 90,
|
|
195
|
+
source: "my_script",
|
|
196
|
+
agent: "my_agent",
|
|
197
|
+
});
|
|
663
198
|
|
|
664
|
-
|
|
665
|
-
# At session start, get personalized brief for agent's current task
|
|
666
|
-
brief = client.handshake(
|
|
667
|
-
agent_id="research_agent_001",
|
|
668
|
-
task="Research publication history for Dr. Jane Smith",
|
|
669
|
-
recent_messages=["Starting literature review..."]
|
|
670
|
-
)
|
|
671
|
-
|
|
672
|
-
print(brief.operating_rules) # Staff namespace rules for this agent
|
|
673
|
-
print(brief.inferred_task_type) # e.g. "research", "verification"
|
|
674
|
-
|
|
675
|
-
for entry in brief.working_memory:
|
|
676
|
-
print(f"{entry.entity_key}: {entry.summary}")
|
|
199
|
+
const fact = await client.query("project/my-app", "status");
|
|
677
200
|
```
|
|
678
201
|
|
|
679
202
|
---
|
|
680
203
|
|
|
681
|
-
##
|
|
204
|
+
## User Operating Rules
|
|
682
205
|
|
|
683
|
-
|
|
206
|
+
Rules are trigger-based instructions that surface only when the agent is about to do a relevant task (e.g. releasing, pushing to CI). Unlike project policies which are always injected, rules match against the current context using keyword triggers.
|
|
684
207
|
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
iranti = IrantiClient(base_url="http://localhost:3001", api_key="your_key")
|
|
691
|
-
ENTITY = "project/my_project"
|
|
692
|
-
|
|
693
|
-
@tool("Write finding to shared memory")
|
|
694
|
-
def write_finding(key: str, value: str, summary: str, confidence: int) -> str:
|
|
695
|
-
"""Write a fact to Iranti so other agents can access it."""
|
|
696
|
-
result = iranti.write(
|
|
697
|
-
entity=ENTITY,
|
|
698
|
-
key=key,
|
|
699
|
-
value={"data": value},
|
|
700
|
-
summary=summary,
|
|
701
|
-
confidence=confidence,
|
|
702
|
-
source="briefing_doc",
|
|
703
|
-
agent="researcher_agent"
|
|
704
|
-
)
|
|
705
|
-
return f"Saved '{key}': {result.action}"
|
|
706
|
-
|
|
707
|
-
@tool("Get all findings")
|
|
708
|
-
def get_all_findings() -> str:
|
|
709
|
-
"""Load all facts from Iranti."""
|
|
710
|
-
facts = iranti.query_all(ENTITY)
|
|
711
|
-
if not facts:
|
|
712
|
-
return "No findings in shared memory."
|
|
713
|
-
lines = [f"[{f['key']}] {f['summary']} (confidence: {f['confidence']})" for f in facts]
|
|
714
|
-
return "\n".join(lines)
|
|
715
|
-
|
|
716
|
-
# Researcher agent: writes to Iranti
|
|
717
|
-
researcher = Agent(
|
|
718
|
-
role="Research Analyst",
|
|
719
|
-
goal="Extract facts from documents and save to shared memory",
|
|
720
|
-
tools=[write_finding],
|
|
721
|
-
llm=LLM(model="gpt-4o-mini")
|
|
722
|
-
)
|
|
208
|
+
```bash
|
|
209
|
+
# Create a rule via MCP (iranti_write_rule tool) or the API
|
|
210
|
+
# Example: remind the agent to use GitHub Releases instead of npm publish
|
|
211
|
+
# triggers: ["publish", "release", "npm"]
|
|
212
|
+
# enforcement: "hard" (required) or "soft" (guidance)
|
|
723
213
|
|
|
724
|
-
#
|
|
725
|
-
|
|
726
|
-
role="Project Analyst",
|
|
727
|
-
goal="Summarize projects using shared memory",
|
|
728
|
-
tools=[get_all_findings],
|
|
729
|
-
llm=LLM(model="gpt-4o-mini")
|
|
730
|
-
)
|
|
214
|
+
# List all rules
|
|
215
|
+
iranti list-rules
|
|
731
216
|
|
|
732
|
-
#
|
|
733
|
-
|
|
734
|
-
crew.kickoff()
|
|
217
|
+
# Remove a rule
|
|
218
|
+
iranti delete-rule no_npm_publish
|
|
735
219
|
```
|
|
736
220
|
|
|
737
|
-
|
|
221
|
+
Rules are stored as `rule/*` entities. During `iranti_attend`, triggers are matched against the current conversation context — single-word triggers match as tokens, multi-word triggers match as phrases.
|
|
738
222
|
|
|
739
223
|
---
|
|
740
224
|
|
|
741
|
-
##
|
|
742
|
-
|
|
743
|
-
Add Iranti memory to Claude, ChatGPT, or any LLM via API wrapper:
|
|
744
|
-
|
|
745
|
-
```python
|
|
746
|
-
from clients.middleware.iranti_middleware import IrantiMiddleware
|
|
747
|
-
|
|
748
|
-
middleware = IrantiMiddleware(
|
|
749
|
-
agent_id="my_agent",
|
|
750
|
-
iranti_url="http://localhost:3001"
|
|
751
|
-
)
|
|
752
|
-
|
|
753
|
-
# Before sending to LLM
|
|
754
|
-
augmented = middleware.before_send(
|
|
755
|
-
user_message="What was the blocker?",
|
|
756
|
-
conversation_history=[...]
|
|
757
|
-
)
|
|
225
|
+
## Diagnostics
|
|
758
226
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
227
|
+
```bash
|
|
228
|
+
iranti doctor # Validate database, API key, and provider
|
|
229
|
+
iranti status # Show known instances and project bindings
|
|
230
|
+
iranti chat # Interactive chat shell for sanity checking
|
|
231
|
+
iranti upgrade --check # Check for available updates
|
|
232
|
+
iranti upgrade --yes # Apply updates
|
|
764
233
|
```
|
|
765
234
|
|
|
766
|
-
|
|
767
|
-
1. `before_send()` calls `attend()` with conversation context
|
|
768
|
-
2. Forgotten facts are prepended as `[MEMORY: ...]`
|
|
769
|
-
3. `after_receive()` extracts new facts and saves them (best-effort)
|
|
770
|
-
4. If the host skips `handshake()` or `attend()`, discovery calls block instead of returning warn-only metadata
|
|
771
|
-
|
|
772
|
-
**Note**: Browser extensions are blocked by ChatGPT and Claude's Content Security Policy. Use API-based middleware instead.
|
|
773
|
-
|
|
774
|
-
**Examples**: [`clients/middleware/claude_example.py`](clients/middleware/claude_example.py)
|
|
235
|
+
Operator-facing CLI help now includes short "what it does" and "use this when" guidance for every command — run `iranti --help` or `iranti <command> --help` for details.
|
|
775
236
|
|
|
776
237
|
---
|
|
777
238
|
|
|
778
|
-
##
|
|
239
|
+
## Configuration
|
|
779
240
|
|
|
780
|
-
|
|
241
|
+
Environment variables (set during `iranti setup` or manually in `.env`):
|
|
781
242
|
|
|
782
|
-
|
|
|
243
|
+
| Variable | Description |
|
|
783
244
|
|---|---|
|
|
784
|
-
|
|
|
785
|
-
|
|
|
786
|
-
|
|
|
787
|
-
|
|
|
788
|
-
|
|
|
789
|
-
|
|
790
|
-
### REST API
|
|
791
|
-
|
|
792
|
-
Express server on port 3001 with endpoints:
|
|
793
|
-
|
|
794
|
-
- `POST /kb/write` - Write atomic fact
|
|
795
|
-
- `POST /kb/ingest` - Ingest raw text for one entity, auto-chunk into facts with per-fact confidence and per-fact write outcomes
|
|
796
|
-
- `GET /kb/query/:entityType/:entityId/:key` - Query specific fact
|
|
797
|
-
- `GET /kb/query/:entityType/:entityId` - Query all facts for entity
|
|
798
|
-
- `GET /kb/search` - Hybrid search across facts
|
|
799
|
-
- `POST /memory/attend` - Decide whether to inject memory for this turn and unlock one discovery step for the current turn
|
|
800
|
-
- `POST /memory/observe` - Context persistence (inject missing facts)
|
|
801
|
-
- `POST /memory/handshake` - Working memory brief for agent session
|
|
802
|
-
- `GET /memory/ledger` - Read structured session ledger events from `staff_events`
|
|
803
|
-
- `GET /memory/sessions` - List persisted operator-visible session checkpoints across agents, with optional operator filters/sorting
|
|
804
|
-
- `GET /memory/session/:agentId` - Inspect the current persisted session checkpoint/recovery state
|
|
805
|
-
- `POST /kb/relate` - Create entity relationship
|
|
806
|
-
- `GET /kb/related/:entityType/:entityId` - Get related entities
|
|
807
|
-
- `POST /agents/register` - Register agent in registry
|
|
808
|
-
|
|
809
|
-
All endpoints require `X-Iranti-Key` header for authentication.
|
|
810
|
-
Discovery endpoints return `428 Precondition Required` when a host skips the required session `handshake` or current-turn `attend`.
|
|
245
|
+
| `DATABASE_URL` | PostgreSQL connection string (pgvector required) |
|
|
246
|
+
| `IRANTI_API_KEY` | Server authentication key |
|
|
247
|
+
| `LLM_PROVIDER` | `openai` \| `claude` \| `gemini` \| `groq` \| `mistral` \| `ollama` \| `mock` |
|
|
248
|
+
| `IRANTI_PORT` | API port (default: `3001`) |
|
|
249
|
+
| `IRANTI_ARCHIVIST_WATCH` | Watch escalation files and auto-run maintenance (`true`/`false`) |
|
|
811
250
|
|
|
812
251
|
---
|
|
813
252
|
|
|
814
|
-
##
|
|
815
|
-
|
|
816
|
-
Six PostgreSQL tables:
|
|
817
|
-
|
|
818
|
-
```
|
|
819
|
-
knowledge_base - current truth (one live row per entity/key)
|
|
820
|
-
archive - temporal and provenance history for superseded, contradicted, escalated, and expired rows
|
|
821
|
-
entity_relationships - directional graph: MEMBER_OF, PART_OF, AUTHORED, etc.
|
|
822
|
-
entities - canonical entity identity registry
|
|
823
|
-
entity_aliases - normalized aliases mapped to canonical entities
|
|
824
|
-
write_receipts - idempotency receipts for requestId replay safety
|
|
825
|
-
```
|
|
826
|
-
|
|
827
|
-
New entity types, relationship types, and fact keys do not require migrations; they are caller-defined strings.
|
|
828
|
-
|
|
829
|
-
**Archive semantics**: When a current fact is superseded or contested, the current row is removed from `knowledge_base` and a closed historical interval is written to `archive`. Temporal queries use `validFrom` / `validUntil` plus archive metadata to answer point-in-time reads.
|
|
830
|
-
|
|
831
|
-
---
|
|
832
|
-
|
|
833
|
-
## Running Tests
|
|
253
|
+
## Uninstall
|
|
834
254
|
|
|
835
255
|
```bash
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
npm run test:attendant # Working memory
|
|
839
|
-
npm run test:reliability # Source scoring
|
|
840
|
-
|
|
841
|
-
# Python validation experiments
|
|
842
|
-
cd clients/experiments
|
|
843
|
-
python validate_nexus_observe.py # Context persistence
|
|
844
|
-
python validate_nexus_treatment.py # Cross-agent transfer
|
|
256
|
+
iranti uninstall --dry-run # Preview what would be removed
|
|
257
|
+
iranti uninstall --all --yes # Remove runtime + project bindings
|
|
845
258
|
```
|
|
846
259
|
|
|
847
260
|
---
|
|
848
261
|
|
|
849
|
-
##
|
|
262
|
+
## Guides
|
|
850
263
|
|
|
851
|
-
|
|
264
|
+
- [Quickstart](docs/guides/quickstart.md)
|
|
265
|
+
- [Claude Code setup](docs/guides/claude-code.md)
|
|
266
|
+
- [Codex CLI setup](docs/guides/codex.md)
|
|
267
|
+
- [GitHub Copilot setup](docs/guides/copilot.md)
|
|
268
|
+
- [Python client](docs/guides/python-client.md)
|
|
269
|
+
- [Security quickstart](docs/guides/security-quickstart.md)
|
|
270
|
+
- [Operator manual](docs/guides/manual.md)
|
|
271
|
+
- [Conflict resolution](docs/guides/conflict-resolution.md)
|
|
272
|
+
- [Cross-tool handoffs](docs/guides/cross-tool-handoffs.md)
|
|
273
|
+
- [Vector backends](docs/guides/vector-backends.md)
|
|
852
274
|
|
|
853
|
-
|
|
854
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
855
|
-
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
856
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
857
|
-
5. Open a Pull Request
|
|
275
|
+
## Links
|
|
858
276
|
|
|
859
|
-
|
|
277
|
+
- [Website](https://iranti.dev)
|
|
278
|
+
- [GitHub](https://github.com/nfemmanuel/iranti)
|
|
279
|
+
- [npm](https://www.npmjs.com/package/iranti)
|
|
280
|
+
- [Python client (PyPI)](https://pypi.org/project/iranti/)
|
|
281
|
+
- [TypeScript SDK](https://www.npmjs.com/package/@iranti/sdk)
|
|
860
282
|
|
|
861
283
|
## License
|
|
862
284
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
Free to use, modify, and distribute under AGPL terms. If you offer Iranti as a hosted service and modify it, AGPL requires publishing those modifications.
|
|
866
|
-
|
|
867
|
-
---
|
|
868
|
-
|
|
869
|
-
## Name
|
|
870
|
-
|
|
871
|
-
Iranti is the Yoruba word for memory and remembrance.
|
|
872
|
-
|
|
873
|
-
---
|
|
874
|
-
|
|
875
|
-
## Project Structure
|
|
876
|
-
|
|
877
|
-
```
|
|
878
|
-
src/
|
|
879
|
-
├── library/ — DB client, queries, relationships, agent registry
|
|
880
|
-
├── librarian/ — Write logic, conflict resolution, reliability
|
|
881
|
-
├── attendant/ — Per-agent working memory, observe() implementation
|
|
882
|
-
├── archivist/ — Periodic cleanup, escalation processing
|
|
883
|
-
├── lib/ — LLM abstraction, model router, providers
|
|
884
|
-
├── sdk/ — Public TypeScript API
|
|
885
|
-
└── api/ — REST API server
|
|
886
|
-
|
|
887
|
-
clients/
|
|
888
|
-
├── python/ — Python client (IrantiClient)
|
|
889
|
-
├── middleware/ — LLM conversation wrappers (Claude, ChatGPT, etc.)
|
|
890
|
-
└── experiments/ — Validated experiments with real results
|
|
891
|
-
|
|
892
|
-
docs/
|
|
893
|
-
└── internal/validation_results.md — Full experiment outputs and analysis
|
|
894
|
-
```
|
|
895
|
-
|
|
896
|
-
---
|
|
897
|
-
|
|
898
|
-
## Support
|
|
899
|
-
|
|
900
|
-
- **Issues**: [GitHub Issues](https://github.com/nfemmanuel/iranti/issues)
|
|
901
|
-
- **Discussions**: [GitHub Discussions](https://github.com/nfemmanuel/iranti/discussions)
|
|
902
|
-
- **Email**: oluwaniifemi.emmanuel@uni.minerva.edu
|
|
903
|
-
- **Changelog**: [`CHANGELOG.md`](CHANGELOG.md)
|
|
904
|
-
|
|
905
|
-
---
|
|
906
|
-
|
|
907
|
-
**Built with ❤️ for the multi-agent AI community.**
|
|
908
|
-
|
|
285
|
+
AGPL-3.0-or-later
|