iranti 0.2.32 → 0.2.33
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 +771 -771
- package/bin/iranti.js +1 -1
- package/dist/scripts/iranti-mcp.js +20 -20
- package/dist/src/api/server.js +1 -1
- package/dist/src/archivist/index.js +9 -9
- package/dist/src/attendant/AttendantInstance.js +54 -54
- package/dist/src/lib/commandInvocation.js +3 -3
- package/dist/src/lib/commandInvocation.js.map +1 -1
- package/dist/src/librarian/index.js +51 -51
- package/dist/src/library/queries.js +85 -85
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
# Iranti
|
|
2
|
-
|
|
3
|
-
[](https://www.gnu.org/licenses/agpl-3.0.en.html)
|
|
4
|
-
[](https://www.python.org/downloads/)
|
|
5
|
-
[](https://www.typescriptlang.org/)
|
|
6
|
-
[](https://www.crewai.com/)
|
|
7
|
-
|
|
8
|
-
**Memory infrastructure for multi-agent AI systems.**
|
|
9
|
-
|
|
10
|
-
Iranti gives agents persistent, identity-based memory. Facts written by one agent are retrievable by any other agent through exact entity+key lookup. Iranti also supports hybrid search (lexical + vector) when exact keys are unknown. Memory persists across sessions and survives context window limits.
|
|
11
|
-
|
|
1
|
+
# Iranti
|
|
2
|
+
|
|
3
|
+
[](https://www.gnu.org/licenses/agpl-3.0.en.html)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://www.crewai.com/)
|
|
7
|
+
|
|
8
|
+
**Memory infrastructure for multi-agent AI systems.**
|
|
9
|
+
|
|
10
|
+
Iranti gives agents persistent, identity-based memory. Facts written by one agent are retrievable by any other agent through exact entity+key lookup. Iranti also supports hybrid search (lexical + vector) when exact keys are unknown. Memory persists across sessions and survives context window limits.
|
|
11
|
+
|
|
12
12
|
**Latest release:** [`v0.2.21`](https://github.com/nfemmanuel/iranti/releases/tag/v0.2.21)
|
|
13
13
|
Published packages:
|
|
14
14
|
- `iranti@0.2.21`
|
|
15
15
|
- `@iranti/sdk@0.2.21`
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## What is Iranti?
|
|
20
|
-
|
|
21
|
-
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).
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Runtime Roles
|
|
26
|
-
|
|
27
|
-
- **User**: Person who interacts with an app or chatbot built on Iranti.
|
|
28
|
-
- **Agent**: External AI worker that writes/reads facts through Iranti APIs.
|
|
29
|
-
- **Attendant**: Per-agent memory manager that decides what to inject for each turn.
|
|
30
|
-
- **Librarian**: Conflict-aware writer that owns all KB writes.
|
|
31
|
-
- **Library**: Active truth store (`knowledge_base`) in PostgreSQL.
|
|
32
|
-
- **Archive**: Historical/superseded truth store (`archive`) in PostgreSQL.
|
|
33
|
-
- **Archivist**: Maintenance worker that archives stale/low-confidence facts and processes resolved escalations.
|
|
34
|
-
- **Resolutionist**: Interactive CLI reviewer that guides humans through pending escalation files and writes valid authoritative resolutions.
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## Why Not a Vector Database?
|
|
39
|
-
|
|
40
|
-
| Feature | Vector DB | Iranti |
|
|
41
|
-
|---|---|---|
|
|
42
|
-
| **Retrieval** | Similarity (nearest neighbor) | Identity-first + optional hybrid search |
|
|
43
|
-
| **Storage** | Embeddings in vector space | Structured facts with keys |
|
|
44
|
-
| **Persistence** | Stateless between calls | Persistent across sessions |
|
|
45
|
-
| **Confidence** | No confidence tracking | Per-fact confidence scores |
|
|
46
|
-
| **Conflicts** | No conflict resolution | Automatic resolution + escalation |
|
|
47
|
-
| **Context** | No context awareness | `observe()` injects missing facts |
|
|
48
|
-
|
|
49
|
-
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.
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## Benchmark Summary
|
|
54
|
-
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## What is Iranti?
|
|
20
|
+
|
|
21
|
+
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).
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Runtime Roles
|
|
26
|
+
|
|
27
|
+
- **User**: Person who interacts with an app or chatbot built on Iranti.
|
|
28
|
+
- **Agent**: External AI worker that writes/reads facts through Iranti APIs.
|
|
29
|
+
- **Attendant**: Per-agent memory manager that decides what to inject for each turn.
|
|
30
|
+
- **Librarian**: Conflict-aware writer that owns all KB writes.
|
|
31
|
+
- **Library**: Active truth store (`knowledge_base`) in PostgreSQL.
|
|
32
|
+
- **Archive**: Historical/superseded truth store (`archive`) in PostgreSQL.
|
|
33
|
+
- **Archivist**: Maintenance worker that archives stale/low-confidence facts and processes resolved escalations.
|
|
34
|
+
- **Resolutionist**: Interactive CLI reviewer that guides humans through pending escalation files and writes valid authoritative resolutions.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Why Not a Vector Database?
|
|
39
|
+
|
|
40
|
+
| Feature | Vector DB | Iranti |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| **Retrieval** | Similarity (nearest neighbor) | Identity-first + optional hybrid search |
|
|
43
|
+
| **Storage** | Embeddings in vector space | Structured facts with keys |
|
|
44
|
+
| **Persistence** | Stateless between calls | Persistent across sessions |
|
|
45
|
+
| **Confidence** | No confidence tracking | Per-fact confidence scores |
|
|
46
|
+
| **Conflicts** | No conflict resolution | Automatic resolution + escalation |
|
|
47
|
+
| **Context** | No context awareness | `observe()` injects missing facts |
|
|
48
|
+
|
|
49
|
+
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.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Benchmark Summary
|
|
54
|
+
|
|
55
55
|
Iranti has now been rerun against a broader benchmark program covering 11 active capability tracks in `v0.2.21`. The current picture is stronger and narrower than the early validation story: exact, durable, shared memory is benchmark-backed; broad semantic-memory and autonomous-memory claims still need tighter boundaries.
|
|
56
|
-
|
|
57
|
-
### Confirmed Strengths
|
|
58
|
-
|
|
56
|
+
|
|
57
|
+
### Confirmed Strengths
|
|
58
|
+
|
|
59
59
|
- **Exact lookup (`iranti_query`)**: Retrieval remains exact and durable across genuine session and process breaks. At tested scale (`N=1938`, about `107k` tokens), the measured advantage is efficiency, not accuracy: Iranti answered `10/10` with zero haystack tokens while the baseline also answered `10/10` after reading the full document.
|
|
60
60
|
- **Persistence across sessions**: Facts survive context-window loss and genuine process boundaries. `iranti_query` remained `8/8` across isolated session breaks in the rerun.
|
|
61
61
|
- **Conflict handling**: Reliable when confidence differentials are large and explicit.
|
|
@@ -72,10 +72,10 @@ Iranti has now been rerun against a broader benchmark program covering 11 active
|
|
|
72
72
|
- **Observe performs better with explicit entity hints than with cold-start discovery.**
|
|
73
73
|
- **Upgrade durability should be scoped carefully.** The `v0.2.21` upgrade procedure reinitialized the instance under test; do not assume KB data survives upgrades without an explicit preservation or migration path.
|
|
74
74
|
- **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.
|
|
75
|
-
|
|
76
|
-
### Practical Position
|
|
77
|
-
|
|
78
|
-
Iranti is strongest today as **structured memory infrastructure for multi-agent systems**:
|
|
75
|
+
|
|
76
|
+
### Practical Position
|
|
77
|
+
|
|
78
|
+
Iranti is strongest today as **structured memory infrastructure for multi-agent systems**:
|
|
79
79
|
- exact entity/key lookup
|
|
80
80
|
- durable shared memory
|
|
81
81
|
- provenance-aware writes
|
|
@@ -83,21 +83,21 @@ Iranti is strongest today as **structured memory infrastructure for multi-agent
|
|
|
83
83
|
- session-aware recovery
|
|
84
84
|
|
|
85
85
|
It should not yet be described as a fully general semantic-memory, semantic-search, or autonomous-memory-injection system.
|
|
86
|
-
|
|
87
|
-
Historical benchmark material remains available here:
|
|
88
|
-
- [`docs/internal/validation_results.md`](docs/internal/validation_results.md)
|
|
89
|
-
- [`docs/internal/MULTI_FRAMEWORK_VALIDATION.md`](docs/internal/MULTI_FRAMEWORK_VALIDATION.md)
|
|
90
|
-
- [`docs/internal/conflict_benchmark.md`](docs/internal/conflict_benchmark.md)
|
|
91
|
-
- [`docs/internal/consistency_model.md`](docs/internal/consistency_model.md)
|
|
92
|
-
|
|
93
|
-
## Gap Analysis
|
|
94
|
-
|
|
95
|
-
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.
|
|
96
|
-
|
|
97
|
-
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.
|
|
98
|
-
|
|
99
|
-
### Where Iranti Is Differentiated
|
|
100
|
-
|
|
86
|
+
|
|
87
|
+
Historical benchmark material remains available here:
|
|
88
|
+
- [`docs/internal/validation_results.md`](docs/internal/validation_results.md)
|
|
89
|
+
- [`docs/internal/MULTI_FRAMEWORK_VALIDATION.md`](docs/internal/MULTI_FRAMEWORK_VALIDATION.md)
|
|
90
|
+
- [`docs/internal/conflict_benchmark.md`](docs/internal/conflict_benchmark.md)
|
|
91
|
+
- [`docs/internal/consistency_model.md`](docs/internal/consistency_model.md)
|
|
92
|
+
|
|
93
|
+
## Gap Analysis
|
|
94
|
+
|
|
95
|
+
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.
|
|
96
|
+
|
|
97
|
+
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.
|
|
98
|
+
|
|
99
|
+
### Where Iranti Is Differentiated
|
|
100
|
+
|
|
101
101
|
- Identity-first fact retrieval through `entityType/entityId + key`
|
|
102
102
|
- Cross-agent fact sharing as a first-class model
|
|
103
103
|
- Conflict-aware writes through the Librarian
|
|
@@ -108,58 +108,58 @@ The current competitive case for Iranti is strongest when a team needs memory th
|
|
|
108
108
|
- Hybrid retrieval when exact keys are unknown
|
|
109
109
|
- Local install + project binding flow for Claude Code and Codex
|
|
110
110
|
- Published npm / PyPI surfaces with machine-level CLI setup
|
|
111
|
-
|
|
112
|
-
### Why That Gap Exists
|
|
113
|
-
|
|
114
|
-
The current landscape splits into three buckets:
|
|
115
|
-
|
|
116
|
-
1. **Memory libraries**
|
|
117
|
-
- Systems like Mem0, Zep, Letta, and framework-native memory layers solve parts of the problem.
|
|
118
|
-
- They usually optimize for semantic retrieval, agent-local memory, or framework integration.
|
|
119
|
-
- They rarely expose deterministic `entity + key` lookup, explicit confidence surfaces, and developer-controlled conflict handling together.
|
|
120
|
-
|
|
121
|
-
2. **Vector databases**
|
|
122
|
-
- Pinecone, Weaviate, Qdrant, Chroma, Milvus, LanceDB, and `pgvector` solve storage and retrieval infrastructure.
|
|
123
|
-
- They do not, by themselves, solve memory semantics such as conflict resolution, context injection, fact lifecycle, or shared agent-facing state.
|
|
124
|
-
|
|
125
|
-
3. **Multi-agent frameworks**
|
|
126
|
-
- CrewAI, LangGraph, AutoGen, CAMEL, MetaGPT, and similar frameworks often include some memory support.
|
|
127
|
-
- In practice, that memory is usually framework-coupled, shallow on conflict semantics, and difficult to reuse outside the framework that created it.
|
|
128
|
-
|
|
129
|
-
### Main Gaps
|
|
130
|
-
|
|
131
|
-
1. **Operational maturity**
|
|
132
|
-
- Local PostgreSQL setup is still a real source of friction.
|
|
133
|
-
- The product needs stronger diagnostics, connection recovery, and less dependence on users debugging local database state by hand.
|
|
134
|
-
|
|
135
|
-
2. **Onboarding still has sharp edges**
|
|
136
|
-
- `iranti setup` is materially better than before, but first-run still assumes too much infrastructure literacy.
|
|
137
|
-
- Managed Postgres paths, cleaner bootstrap verification, and fewer environment-level surprises are still needed.
|
|
138
|
-
|
|
139
|
-
3. **No operator UI yet**
|
|
140
|
-
- Iranti is still CLI-first.
|
|
141
|
-
- There is no control plane yet for provider keys, project bindings, integrations, memory inspection, and escalation review.
|
|
142
|
-
|
|
143
|
-
4. **Adoption proof is still early**
|
|
144
|
-
- The repo has validation experiments and real local end-to-end usage, but broad production adoption is still limited.
|
|
145
|
-
- The next product truth has to come from external users and real workloads, not more speculative architecture alone.
|
|
146
|
-
|
|
147
|
-
5. **Hosted product is not built**
|
|
148
|
-
- Open-source/local infrastructure is the active surface today.
|
|
149
|
-
- Hosted deployment, multi-tenant operations, billing, and cloud onboarding remain future work.
|
|
150
|
-
|
|
151
|
-
6. **Graph-native reasoning is still limited**
|
|
152
|
-
- Iranti supports explicit entity relationships today.
|
|
153
|
-
- It does not yet compete with graph-first systems on temporal graph traversal or graph-native reasoning depth.
|
|
154
|
-
|
|
155
|
-
7. **Memory extraction is not the main model**
|
|
156
|
-
- Iranti supports structured writes and ingest/chunking, but it is not primarily a "dump arbitrary conversations in and auto-magically derive perfect memory" system.
|
|
157
|
-
- That is a deliberate tradeoff in favor of explicit, inspectable facts, but it increases integration work.
|
|
158
|
-
|
|
159
|
-
### Current Position
|
|
160
|
-
|
|
161
|
-
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:
|
|
162
|
-
|
|
111
|
+
|
|
112
|
+
### Why That Gap Exists
|
|
113
|
+
|
|
114
|
+
The current landscape splits into three buckets:
|
|
115
|
+
|
|
116
|
+
1. **Memory libraries**
|
|
117
|
+
- Systems like Mem0, Zep, Letta, and framework-native memory layers solve parts of the problem.
|
|
118
|
+
- They usually optimize for semantic retrieval, agent-local memory, or framework integration.
|
|
119
|
+
- They rarely expose deterministic `entity + key` lookup, explicit confidence surfaces, and developer-controlled conflict handling together.
|
|
120
|
+
|
|
121
|
+
2. **Vector databases**
|
|
122
|
+
- Pinecone, Weaviate, Qdrant, Chroma, Milvus, LanceDB, and `pgvector` solve storage and retrieval infrastructure.
|
|
123
|
+
- They do not, by themselves, solve memory semantics such as conflict resolution, context injection, fact lifecycle, or shared agent-facing state.
|
|
124
|
+
|
|
125
|
+
3. **Multi-agent frameworks**
|
|
126
|
+
- CrewAI, LangGraph, AutoGen, CAMEL, MetaGPT, and similar frameworks often include some memory support.
|
|
127
|
+
- In practice, that memory is usually framework-coupled, shallow on conflict semantics, and difficult to reuse outside the framework that created it.
|
|
128
|
+
|
|
129
|
+
### Main Gaps
|
|
130
|
+
|
|
131
|
+
1. **Operational maturity**
|
|
132
|
+
- Local PostgreSQL setup is still a real source of friction.
|
|
133
|
+
- The product needs stronger diagnostics, connection recovery, and less dependence on users debugging local database state by hand.
|
|
134
|
+
|
|
135
|
+
2. **Onboarding still has sharp edges**
|
|
136
|
+
- `iranti setup` is materially better than before, but first-run still assumes too much infrastructure literacy.
|
|
137
|
+
- Managed Postgres paths, cleaner bootstrap verification, and fewer environment-level surprises are still needed.
|
|
138
|
+
|
|
139
|
+
3. **No operator UI yet**
|
|
140
|
+
- Iranti is still CLI-first.
|
|
141
|
+
- There is no control plane yet for provider keys, project bindings, integrations, memory inspection, and escalation review.
|
|
142
|
+
|
|
143
|
+
4. **Adoption proof is still early**
|
|
144
|
+
- The repo has validation experiments and real local end-to-end usage, but broad production adoption is still limited.
|
|
145
|
+
- The next product truth has to come from external users and real workloads, not more speculative architecture alone.
|
|
146
|
+
|
|
147
|
+
5. **Hosted product is not built**
|
|
148
|
+
- Open-source/local infrastructure is the active surface today.
|
|
149
|
+
- Hosted deployment, multi-tenant operations, billing, and cloud onboarding remain future work.
|
|
150
|
+
|
|
151
|
+
6. **Graph-native reasoning is still limited**
|
|
152
|
+
- Iranti supports explicit entity relationships today.
|
|
153
|
+
- It does not yet compete with graph-first systems on temporal graph traversal or graph-native reasoning depth.
|
|
154
|
+
|
|
155
|
+
7. **Memory extraction is not the main model**
|
|
156
|
+
- Iranti supports structured writes and ingest/chunking, but it is not primarily a "dump arbitrary conversations in and auto-magically derive perfect memory" system.
|
|
157
|
+
- That is a deliberate tradeoff in favor of explicit, inspectable facts, but it increases integration work.
|
|
158
|
+
|
|
159
|
+
### Current Position
|
|
160
|
+
|
|
161
|
+
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:
|
|
162
|
+
|
|
163
163
|
- exact cross-agent fact transfer works at meaningful context scales
|
|
164
164
|
- facts survive session loss and genuine process breaks
|
|
165
165
|
- same-key conflicting writes are serialized and observable
|
|
@@ -167,30 +167,30 @@ Iranti is strongest today as infrastructure for developers building multi-agent
|
|
|
167
167
|
- attended recovery works with explicit hints, while autonomous attend classification remains a known defect
|
|
168
168
|
|
|
169
169
|
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.
|
|
170
|
-
|
|
171
|
-
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.
|
|
172
|
-
|
|
173
|
-
## Quickstart
|
|
174
|
-
|
|
170
|
+
|
|
171
|
+
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.
|
|
172
|
+
|
|
173
|
+
## Quickstart
|
|
174
|
+
|
|
175
175
|
**Requirements**: Node.js 18+, PostgreSQL with pgvector support, Python 3.8+
|
|
176
|
-
|
|
177
|
-
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.
|
|
178
|
-
|
|
179
|
-
```bash
|
|
180
|
-
# 1. Install the CLI
|
|
181
|
-
npm install -g iranti
|
|
182
|
-
|
|
183
|
-
# 2. Run the guided setup
|
|
184
|
-
iranti setup
|
|
185
|
-
|
|
186
|
-
# 3. Start the instance
|
|
187
|
-
iranti run --instance local
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
`iranti setup` now defaults to an isolated per-project runtime. Shared machine-level instances are still supported, but they are now an explicit choice rather than the default.
|
|
191
|
-
|
|
176
|
+
|
|
177
|
+
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.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# 1. Install the CLI
|
|
181
|
+
npm install -g iranti
|
|
182
|
+
|
|
183
|
+
# 2. Run the guided setup
|
|
184
|
+
iranti setup
|
|
185
|
+
|
|
186
|
+
# 3. Start the instance
|
|
187
|
+
iranti run --instance local
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`iranti setup` now defaults to an isolated per-project runtime. Shared machine-level instances are still supported, but they are now an explicit choice rather than the default.
|
|
191
|
+
|
|
192
192
|
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.
|
|
193
|
-
|
|
193
|
+
|
|
194
194
|
Long-running agents can now checkpoint and recover interrupted work. Programmatic session lifecycle methods are available through the SDK and REST API:
|
|
195
195
|
- `checkpoint()`
|
|
196
196
|
- `inspectSession()`
|
|
@@ -198,16 +198,16 @@ Long-running agents can now checkpoint and recover interrupted work. Programmati
|
|
|
198
198
|
- `resumeSession()`
|
|
199
199
|
- `completeSession()`
|
|
200
200
|
- `abandonSession()`
|
|
201
|
-
|
|
202
|
-
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:
|
|
203
|
-
|
|
204
|
-
```bash
|
|
205
|
-
iranti upgrade --restart --instance local
|
|
206
|
-
```
|
|
207
|
-
|
|
201
|
+
|
|
202
|
+
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:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
iranti upgrade --restart --instance local
|
|
206
|
+
```
|
|
207
|
+
|
|
208
208
|
If something still fails and you need more detail, use:
|
|
209
|
-
|
|
210
|
-
```bash
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
211
|
iranti doctor --debug
|
|
212
212
|
iranti run --instance local --debug
|
|
213
213
|
iranti upgrade --verbose
|
|
@@ -221,187 +221,187 @@ iranti uninstall --all --yes
|
|
|
221
221
|
```
|
|
222
222
|
|
|
223
223
|
Default uninstall keeps runtime data and project bindings. `--all` removes discovered runtime roots plus project-local Iranti integrations.
|
|
224
|
-
|
|
225
|
-
Advanced/manual path:
|
|
226
|
-
|
|
227
|
-
```bash
|
|
228
|
-
# 1. Clone and configure
|
|
229
|
-
git clone https://github.com/nfemmanuel/iranti
|
|
230
|
-
cd iranti
|
|
231
|
-
cp .env.example .env # Set DATABASE_URL and IRANTI_API_KEY
|
|
232
|
-
|
|
233
|
-
# Optional runtime hygiene
|
|
234
|
-
# IRANTI_ESCALATION_DIR=C:/Users/<you>/.iranti/escalation
|
|
235
|
-
# IRANTI_ARCHIVIST_WATCH=true
|
|
236
|
-
# IRANTI_ARCHIVIST_DEBOUNCE_MS=60000
|
|
237
|
-
# IRANTI_ARCHIVIST_INTERVAL_MS=21600000
|
|
238
|
-
|
|
239
|
-
# 2. Start PostgreSQL
|
|
240
|
-
docker-compose up -d
|
|
241
|
-
|
|
242
|
-
# 3. Install and initialize
|
|
243
|
-
npm install
|
|
244
|
-
npm run setup # Runs migrations
|
|
245
|
-
|
|
246
|
-
# 4. Start API server
|
|
247
|
-
npm run api # Runs on port 3001
|
|
248
|
-
|
|
249
|
-
# 5. Install Python client
|
|
250
|
-
pip install iranti
|
|
251
|
-
|
|
252
|
-
# Optional: install the TypeScript client
|
|
253
|
-
npm install @iranti/sdk
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### Archivist Scheduling Knobs
|
|
257
|
-
|
|
258
|
-
- `IRANTI_ARCHIVIST_WATCH=true` enables file-change watching on escalation `active/`.
|
|
259
|
-
- `IRANTI_ARCHIVIST_DEBOUNCE_MS=60000` runs maintenance 60s after the latest file change.
|
|
260
|
-
- `IRANTI_ARCHIVIST_INTERVAL_MS=21600000` runs maintenance every 6 hours (set `0` to disable).
|
|
261
|
-
- `IRANTI_ESCALATION_DIR` sets escalation storage root. Default is `~/.iranti/escalation`, keeping escalation files out of the repo by default.
|
|
262
|
-
|
|
263
|
-
### Per-User API Keys (Recommended)
|
|
264
|
-
|
|
265
|
-
```bash
|
|
266
|
-
# Create a key for one user/app (prints token once)
|
|
267
|
-
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"
|
|
268
|
-
|
|
269
|
-
# List keys
|
|
270
|
-
npm run api-key:list
|
|
271
|
-
|
|
272
|
-
# Revoke a key
|
|
273
|
-
npm run api-key:revoke -- --key-id chatbot_alice
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
Use the printed token (`keyId.secret`) as `X-Iranti-Key`.
|
|
277
|
-
Scopes use `resource:action` format (for example `kb:read`, `memory:write`, `metrics:read`, `proxy:chat`).
|
|
278
|
-
|
|
279
|
-
### Security Baseline
|
|
280
|
-
|
|
281
|
-
- Use one scoped key per app/service identity.
|
|
282
|
-
- Rotate any key that is exposed in logs, screenshots, or chat.
|
|
283
|
-
- Keep escalation/log paths outside the repo working tree.
|
|
284
|
-
- Use TLS/reverse proxy for non-local deployments.
|
|
285
|
-
|
|
286
|
-
Security quickstart: [`docs/guides/security-quickstart.md`](docs/guides/security-quickstart.md)
|
|
287
|
-
Operator manual: [`docs/guides/manual.md`](docs/guides/manual.md)
|
|
288
|
-
Claude Code guide: [`docs/guides/claude-code.md`](docs/guides/claude-code.md)
|
|
289
|
-
Codex guide: [`docs/guides/codex.md`](docs/guides/codex.md)
|
|
290
|
-
Release guide: [`docs/guides/releasing.md`](docs/guides/releasing.md)
|
|
291
|
-
Vector backend guide: [`docs/guides/vector-backends.md`](docs/guides/vector-backends.md)
|
|
292
|
-
|
|
293
|
-
### Claude Code via MCP
|
|
294
|
-
|
|
295
|
-
Iranti ships a local stdio MCP server for Claude Code and other MCP clients:
|
|
296
|
-
|
|
297
|
-
```bash
|
|
298
|
-
iranti mcp
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
Use it with a project-local `.mcp.json`, and optionally add `iranti claude-hook` for `SessionStart` and `UserPromptSubmit`.
|
|
302
|
-
|
|
303
|
-
Fast path:
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
iranti claude-setup
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
Guide: [`docs/guides/claude-code.md`](docs/guides/claude-code.md)
|
|
310
|
-
|
|
311
|
-
### Codex via MCP
|
|
312
|
-
|
|
224
|
+
|
|
225
|
+
Advanced/manual path:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# 1. Clone and configure
|
|
229
|
+
git clone https://github.com/nfemmanuel/iranti
|
|
230
|
+
cd iranti
|
|
231
|
+
cp .env.example .env # Set DATABASE_URL and IRANTI_API_KEY
|
|
232
|
+
|
|
233
|
+
# Optional runtime hygiene
|
|
234
|
+
# IRANTI_ESCALATION_DIR=C:/Users/<you>/.iranti/escalation
|
|
235
|
+
# IRANTI_ARCHIVIST_WATCH=true
|
|
236
|
+
# IRANTI_ARCHIVIST_DEBOUNCE_MS=60000
|
|
237
|
+
# IRANTI_ARCHIVIST_INTERVAL_MS=21600000
|
|
238
|
+
|
|
239
|
+
# 2. Start PostgreSQL
|
|
240
|
+
docker-compose up -d
|
|
241
|
+
|
|
242
|
+
# 3. Install and initialize
|
|
243
|
+
npm install
|
|
244
|
+
npm run setup # Runs migrations
|
|
245
|
+
|
|
246
|
+
# 4. Start API server
|
|
247
|
+
npm run api # Runs on port 3001
|
|
248
|
+
|
|
249
|
+
# 5. Install Python client
|
|
250
|
+
pip install iranti
|
|
251
|
+
|
|
252
|
+
# Optional: install the TypeScript client
|
|
253
|
+
npm install @iranti/sdk
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Archivist Scheduling Knobs
|
|
257
|
+
|
|
258
|
+
- `IRANTI_ARCHIVIST_WATCH=true` enables file-change watching on escalation `active/`.
|
|
259
|
+
- `IRANTI_ARCHIVIST_DEBOUNCE_MS=60000` runs maintenance 60s after the latest file change.
|
|
260
|
+
- `IRANTI_ARCHIVIST_INTERVAL_MS=21600000` runs maintenance every 6 hours (set `0` to disable).
|
|
261
|
+
- `IRANTI_ESCALATION_DIR` sets escalation storage root. Default is `~/.iranti/escalation`, keeping escalation files out of the repo by default.
|
|
262
|
+
|
|
263
|
+
### Per-User API Keys (Recommended)
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Create a key for one user/app (prints token once)
|
|
267
|
+
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"
|
|
268
|
+
|
|
269
|
+
# List keys
|
|
270
|
+
npm run api-key:list
|
|
271
|
+
|
|
272
|
+
# Revoke a key
|
|
273
|
+
npm run api-key:revoke -- --key-id chatbot_alice
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Use the printed token (`keyId.secret`) as `X-Iranti-Key`.
|
|
277
|
+
Scopes use `resource:action` format (for example `kb:read`, `memory:write`, `metrics:read`, `proxy:chat`).
|
|
278
|
+
|
|
279
|
+
### Security Baseline
|
|
280
|
+
|
|
281
|
+
- Use one scoped key per app/service identity.
|
|
282
|
+
- Rotate any key that is exposed in logs, screenshots, or chat.
|
|
283
|
+
- Keep escalation/log paths outside the repo working tree.
|
|
284
|
+
- Use TLS/reverse proxy for non-local deployments.
|
|
285
|
+
|
|
286
|
+
Security quickstart: [`docs/guides/security-quickstart.md`](docs/guides/security-quickstart.md)
|
|
287
|
+
Operator manual: [`docs/guides/manual.md`](docs/guides/manual.md)
|
|
288
|
+
Claude Code guide: [`docs/guides/claude-code.md`](docs/guides/claude-code.md)
|
|
289
|
+
Codex guide: [`docs/guides/codex.md`](docs/guides/codex.md)
|
|
290
|
+
Release guide: [`docs/guides/releasing.md`](docs/guides/releasing.md)
|
|
291
|
+
Vector backend guide: [`docs/guides/vector-backends.md`](docs/guides/vector-backends.md)
|
|
292
|
+
|
|
293
|
+
### Claude Code via MCP
|
|
294
|
+
|
|
295
|
+
Iranti ships a local stdio MCP server for Claude Code and other MCP clients:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
iranti mcp
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Use it with a project-local `.mcp.json`, and optionally add `iranti claude-hook` for `SessionStart` and `UserPromptSubmit`.
|
|
302
|
+
|
|
303
|
+
Fast path:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
iranti claude-setup
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Guide: [`docs/guides/claude-code.md`](docs/guides/claude-code.md)
|
|
310
|
+
|
|
311
|
+
### Codex via MCP
|
|
312
|
+
|
|
313
313
|
Codex uses a global MCP registry rather than a project-local `.mcp.json`. Register Iranti once, then launch Codex in the bound project so `.env.iranti` is in scope:
|
|
314
|
-
|
|
315
|
-
```bash
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
316
|
iranti codex-setup
|
|
317
317
|
codex -C /path/to/your/project
|
|
318
318
|
```
|
|
319
319
|
|
|
320
320
|
By default, `iranti codex-setup` does not pin a project binding globally. `iranti mcp` resolves `.env.iranti` from the active project/workspace at runtime. Use `--project-env` only if you deliberately want to pin Codex globally to one project binding.
|
|
321
|
-
|
|
322
|
-
Alias:
|
|
323
|
-
|
|
324
|
-
```bash
|
|
325
|
-
iranti integrate codex
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
Guide: [`docs/guides/codex.md`](docs/guides/codex.md)
|
|
329
|
-
|
|
330
|
-
### Resolve Pending Escalations
|
|
331
|
-
|
|
332
|
-
Review unresolved human-escalation files from the CLI:
|
|
333
|
-
|
|
334
|
-
```bash
|
|
335
|
-
iranti resolve
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
Use `--dir` to point at a non-default escalation root. Guide: [`docs/guides/conflict-resolution.md`](docs/guides/conflict-resolution.md)
|
|
339
|
-
|
|
340
|
-
### Native Chat
|
|
341
|
-
|
|
342
|
-
Start a CLI chat session against the configured Iranti instance:
|
|
343
|
-
|
|
344
|
-
```bash
|
|
345
|
-
iranti chat
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
Use `--agent`, `--provider`, and `--model` to pin the session identity and model routing.
|
|
349
|
-
The chat surface now includes slash commands for fact history, relationships, conflict-resolution handoff, and confidence updates in addition to memory search/write operations.
|
|
350
|
-
Guide: [`docs/guides/chat.md`](docs/guides/chat.md)
|
|
351
|
-
|
|
352
|
-
### Manual Attendant Inspection
|
|
353
|
-
|
|
354
|
-
For debugging and operator visibility, Iranti also exposes manual Attendant commands:
|
|
355
|
-
|
|
356
|
-
```bash
|
|
357
|
-
iranti handshake --task "Working on ProofScript repo"
|
|
358
|
-
iranti attend "What did we decide about the parser?" --context-file transcript.txt
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
Both commands accept `--json`.
|
|
362
|
-
They are useful for verifying what the Attendant would load or inject for a given agent and project binding.
|
|
363
|
-
They are not a replacement for Claude Code hooks or MCP tools in normal use.
|
|
364
|
-
|
|
365
|
-
---
|
|
366
|
-
|
|
367
|
-
## Install Strategy (Double Layer)
|
|
368
|
-
|
|
369
|
-
Iranti now supports a two-layer install flow:
|
|
370
|
-
|
|
371
|
-
1. **Machine/runtime layer**: one local runtime root with one or more named Iranti instances.
|
|
372
|
-
2. **Project layer**: each chatbot/app binds to one instance with a local `.env.iranti`.
|
|
373
|
-
|
|
374
|
-
### 1) Install CLI
|
|
375
|
-
|
|
376
|
-
```bash
|
|
377
|
-
# If published package is available
|
|
378
|
-
npm install -g iranti
|
|
379
|
-
|
|
380
|
-
# Or from this repo (local simulation)
|
|
381
|
-
npm install -g .
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
### 2) Initialize machine runtime root
|
|
385
|
-
|
|
386
|
-
```bash
|
|
387
|
-
iranti setup
|
|
388
|
-
|
|
389
|
-
# non-interactive automation
|
|
390
|
-
iranti setup --defaults --db-url "postgresql://postgres:realpassword@localhost:5432/iranti_local"
|
|
391
|
-
iranti setup --config ./iranti.setup.json
|
|
392
|
-
|
|
393
|
-
# or, if you want the lower-level manual path:
|
|
394
|
-
iranti install --scope user
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
`iranti setup` is the recommended first-run path. It walks through:
|
|
398
|
-
- shared vs isolated runtime setup
|
|
399
|
-
- instance creation or update
|
|
400
|
-
- API port selection with conflict detection and next-free suggestions
|
|
401
|
-
- database onboarding:
|
|
402
|
-
- existing Postgres
|
|
403
|
-
- managed Postgres
|
|
404
|
-
- optional Docker-hosted Postgres for local development
|
|
321
|
+
|
|
322
|
+
Alias:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
iranti integrate codex
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Guide: [`docs/guides/codex.md`](docs/guides/codex.md)
|
|
329
|
+
|
|
330
|
+
### Resolve Pending Escalations
|
|
331
|
+
|
|
332
|
+
Review unresolved human-escalation files from the CLI:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
iranti resolve
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Use `--dir` to point at a non-default escalation root. Guide: [`docs/guides/conflict-resolution.md`](docs/guides/conflict-resolution.md)
|
|
339
|
+
|
|
340
|
+
### Native Chat
|
|
341
|
+
|
|
342
|
+
Start a CLI chat session against the configured Iranti instance:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
iranti chat
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Use `--agent`, `--provider`, and `--model` to pin the session identity and model routing.
|
|
349
|
+
The chat surface now includes slash commands for fact history, relationships, conflict-resolution handoff, and confidence updates in addition to memory search/write operations.
|
|
350
|
+
Guide: [`docs/guides/chat.md`](docs/guides/chat.md)
|
|
351
|
+
|
|
352
|
+
### Manual Attendant Inspection
|
|
353
|
+
|
|
354
|
+
For debugging and operator visibility, Iranti also exposes manual Attendant commands:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
iranti handshake --task "Working on ProofScript repo"
|
|
358
|
+
iranti attend "What did we decide about the parser?" --context-file transcript.txt
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Both commands accept `--json`.
|
|
362
|
+
They are useful for verifying what the Attendant would load or inject for a given agent and project binding.
|
|
363
|
+
They are not a replacement for Claude Code hooks or MCP tools in normal use.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Install Strategy (Double Layer)
|
|
368
|
+
|
|
369
|
+
Iranti now supports a two-layer install flow:
|
|
370
|
+
|
|
371
|
+
1. **Machine/runtime layer**: one local runtime root with one or more named Iranti instances.
|
|
372
|
+
2. **Project layer**: each chatbot/app binds to one instance with a local `.env.iranti`.
|
|
373
|
+
|
|
374
|
+
### 1) Install CLI
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
# If published package is available
|
|
378
|
+
npm install -g iranti
|
|
379
|
+
|
|
380
|
+
# Or from this repo (local simulation)
|
|
381
|
+
npm install -g .
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### 2) Initialize machine runtime root
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
iranti setup
|
|
388
|
+
|
|
389
|
+
# non-interactive automation
|
|
390
|
+
iranti setup --defaults --db-url "postgresql://postgres:realpassword@localhost:5432/iranti_local"
|
|
391
|
+
iranti setup --config ./iranti.setup.json
|
|
392
|
+
|
|
393
|
+
# or, if you want the lower-level manual path:
|
|
394
|
+
iranti install --scope user
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
`iranti setup` is the recommended first-run path. It walks through:
|
|
398
|
+
- shared vs isolated runtime setup
|
|
399
|
+
- instance creation or update
|
|
400
|
+
- API port selection with conflict detection and next-free suggestions
|
|
401
|
+
- database onboarding:
|
|
402
|
+
- existing Postgres
|
|
403
|
+
- managed Postgres
|
|
404
|
+
- optional Docker-hosted Postgres for local development
|
|
405
405
|
- provider API keys
|
|
406
406
|
- Iranti client API key generation
|
|
407
407
|
- one or more project bindings
|
|
@@ -410,456 +410,456 @@ iranti install --scope user
|
|
|
410
410
|
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.
|
|
411
411
|
|
|
412
412
|
For automation:
|
|
413
|
-
- `iranti setup --defaults` uses sensible defaults plus environment/flag input, but still requires a real `DATABASE_URL`.
|
|
414
|
-
- `iranti setup --config <file>` reads a JSON setup plan for repeatable bootstrap.
|
|
415
|
-
- `--bootstrap-db` runs migrations and seeding during automated setup when the database is reachable.
|
|
416
|
-
- Example config: [docs/guides/iranti.setup.example.json](docs/guides/iranti.setup.example.json)
|
|
417
|
-
|
|
418
|
-
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.
|
|
419
|
-
|
|
420
|
-
Defaults:
|
|
421
|
-
- Windows user scope: `%USERPROFILE%\\.iranti`
|
|
422
|
-
- Windows system scope: `%ProgramData%\\Iranti`
|
|
423
|
-
- Linux system scope: `/var/lib/iranti`
|
|
424
|
-
- macOS system scope: `/Library/Application Support/Iranti`
|
|
425
|
-
|
|
426
|
-
### 3) Create a named instance
|
|
427
|
-
|
|
428
|
-
```bash
|
|
429
|
-
iranti instance create local --port 3001 --db-url "postgresql://postgres:yourpassword@localhost:5432/iranti_local" --provider mock
|
|
430
|
-
iranti instance show local
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
Finish onboarding or change settings later with:
|
|
434
|
-
|
|
435
|
-
```bash
|
|
436
|
-
# Provider/db updates
|
|
413
|
+
- `iranti setup --defaults` uses sensible defaults plus environment/flag input, but still requires a real `DATABASE_URL`.
|
|
414
|
+
- `iranti setup --config <file>` reads a JSON setup plan for repeatable bootstrap.
|
|
415
|
+
- `--bootstrap-db` runs migrations and seeding during automated setup when the database is reachable.
|
|
416
|
+
- Example config: [docs/guides/iranti.setup.example.json](docs/guides/iranti.setup.example.json)
|
|
417
|
+
|
|
418
|
+
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.
|
|
419
|
+
|
|
420
|
+
Defaults:
|
|
421
|
+
- Windows user scope: `%USERPROFILE%\\.iranti`
|
|
422
|
+
- Windows system scope: `%ProgramData%\\Iranti`
|
|
423
|
+
- Linux system scope: `/var/lib/iranti`
|
|
424
|
+
- macOS system scope: `/Library/Application Support/Iranti`
|
|
425
|
+
|
|
426
|
+
### 3) Create a named instance
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
iranti instance create local --port 3001 --db-url "postgresql://postgres:yourpassword@localhost:5432/iranti_local" --provider mock
|
|
430
|
+
iranti instance show local
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Finish onboarding or change settings later with:
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
# Provider/db updates
|
|
437
437
|
iranti configure instance local --provider openai --provider-key replace-with-real-openai-key --db-url "postgresql://postgres:realpassword@localhost:5432/iranti_local"
|
|
438
|
-
iranti configure instance local --interactive
|
|
439
|
-
|
|
440
|
-
# Provider key shortcuts
|
|
441
|
-
iranti list api-keys --instance local
|
|
442
|
-
iranti add api-key openai --instance local
|
|
443
|
-
iranti update api-key claude --instance local
|
|
444
|
-
iranti remove api-key gemini --instance local
|
|
445
|
-
|
|
446
|
-
# Create a registry-backed API key and sync it into the instance env
|
|
447
|
-
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
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
`iranti add|update|remove api-key` updates the stored upstream provider credentials in the instance env without hand-editing `.env` files. `iranti list api-keys` shows which provider keys are currently stored. Supported remote providers are OpenAI, Claude, Gemini, Groq, and Mistral. `mock` and `ollama` do not require remote API keys, and Perplexity is not yet supported.
|
|
451
|
-
|
|
452
|
-
### 4) Run Iranti from that instance
|
|
453
|
-
|
|
454
|
-
```bash
|
|
455
|
-
iranti run --instance local
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
If a provider rejects requests because credits are exhausted, billing is disabled, or the account is quota-limited, Iranti now surfaces a direct message such as `OpenAI quota or billing limit reached. Add credits, update the API key, or switch providers.`
|
|
459
|
-
|
|
460
|
-
### 5) Bind any chatbot/app project to that instance
|
|
461
|
-
|
|
462
|
-
```bash
|
|
463
|
-
cd /path/to/your/chatbot
|
|
464
|
-
iranti project init . --instance local --agent-id chatbot_main
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
This writes `.env.iranti` in the project with the correct `IRANTI_URL`, `IRANTI_API_KEY`, and default agent identity.
|
|
468
|
-
|
|
469
|
-
Later changes use the same surface:
|
|
470
|
-
|
|
471
|
-
```bash
|
|
472
|
-
iranti configure project . --instance local --agent-id chatbot_worker
|
|
473
|
-
iranti configure project . --interactive
|
|
474
|
-
iranti auth create-key --instance local --key-id chatbot_worker --owner "Chatbot Worker" --scopes "kb:read,memory:read,memory:write" --project .
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
For multi-agent systems, bind once per project and set unique agent IDs per worker (for example `planner_agent`, `research_agent`, `critic_agent`).
|
|
478
|
-
|
|
479
|
-
### Installation Diagnostics
|
|
480
|
-
|
|
481
|
-
Use the CLI doctor command before first run or before a release check:
|
|
482
|
-
|
|
483
|
-
```bash
|
|
484
|
-
iranti doctor
|
|
485
|
-
iranti doctor --instance local
|
|
486
|
-
iranti status
|
|
487
|
-
iranti upgrade --check
|
|
488
|
-
iranti upgrade --dry-run
|
|
489
|
-
iranti upgrade --yes
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
This validates the active env file, database URL, API key presence, provider selection, and provider-specific credentials.
|
|
493
|
-
`iranti status` shows the current runtime root, known instances, and local binding files.
|
|
494
|
-
`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`.
|
|
495
|
-
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.
|
|
496
|
-
`iranti configure ...` updates instance/project credentials without manual env editing.
|
|
497
|
-
`iranti auth ...` manages registry-backed API keys and can sync them into instance or project bindings.
|
|
498
|
-
|
|
499
|
-
---
|
|
500
|
-
|
|
501
|
-
## Core API
|
|
502
|
-
|
|
503
|
-
### Write a Fact
|
|
504
|
-
|
|
505
|
-
```python
|
|
506
|
-
from clients.python.iranti import IrantiClient
|
|
507
|
-
|
|
508
|
-
client = IrantiClient(
|
|
509
|
-
base_url="http://localhost:3001",
|
|
510
|
-
api_key="your_api_key_here"
|
|
511
|
-
)
|
|
512
|
-
|
|
513
|
-
result = client.write(
|
|
514
|
-
entity="researcher/jane_smith", # Format: entityType/entityId
|
|
515
|
-
key="affiliation",
|
|
516
|
-
value={"institution": "MIT", "department": "CSAIL"},
|
|
517
|
-
summary="Affiliated with MIT CSAIL", # Compressed for working memory
|
|
518
|
-
confidence=85, # 0-100
|
|
519
|
-
source="OpenAlex",
|
|
520
|
-
agent="research_agent_001"
|
|
521
|
-
)
|
|
522
|
-
|
|
523
|
-
print(result.action) # 'created', 'updated', 'escalated', or 'rejected'
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
### Query a Fact
|
|
527
|
-
|
|
528
|
-
```python
|
|
529
|
-
result = client.query("researcher/jane_smith", "affiliation")
|
|
530
|
-
|
|
531
|
-
if result.found:
|
|
532
|
-
print(result.value) # {"institution": "MIT", "department": "CSAIL"}
|
|
533
|
-
print(result.confidence) # 85
|
|
534
|
-
print(result.source) # "OpenAlex"
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
### Query All Facts for an Entity
|
|
538
|
-
|
|
539
|
-
```python
|
|
540
|
-
facts = client.query_all("researcher/jane_smith")
|
|
541
|
-
|
|
542
|
-
for fact in facts:
|
|
543
|
-
print(f"[{fact['key']}] {fact['summary']} (confidence: {fact['confidence']})")
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
### Graph Traversal
|
|
547
|
-
|
|
548
|
-
```python
|
|
549
|
-
from clients.python.iranti import IrantiClient
|
|
550
|
-
|
|
551
|
-
client = IrantiClient(base_url="http://localhost:3001", api_key="your_api_key_here")
|
|
552
|
-
|
|
553
|
-
# Agent 1 writes facts and links them into a graph.
|
|
554
|
-
client.write("researcher/jane_smith", "affiliation", {"lab": "CSAIL"}, "Jane Smith is affiliated with CSAIL", 90, "OpenAlex", "research_agent")
|
|
555
|
-
client.write("project/quantum_bridge", "status", {"phase": "active"}, "Quantum Bridge is active", 88, "project_brief", "research_agent")
|
|
556
|
-
|
|
557
|
-
client.relate("researcher/jane_smith", "MEMBER_OF", "lab/csail", created_by="research_agent")
|
|
558
|
-
client.relate("lab/csail", "LEADS", "project/quantum_bridge", created_by="research_agent")
|
|
559
|
-
|
|
560
|
-
# Agent 2 starts cold and traverses outward from Jane Smith.
|
|
561
|
-
one_hop = client.related("researcher/jane_smith")
|
|
562
|
-
labs = [f"{r['toType']}/{r['toId']}" for r in one_hop if r["relationshipType"] == "MEMBER_OF"]
|
|
563
|
-
|
|
564
|
-
projects = []
|
|
565
|
-
for lab in labs:
|
|
566
|
-
for rel in client.related(lab):
|
|
567
|
-
if rel["relationshipType"] == "LEADS":
|
|
568
|
-
project = f"{rel['toType']}/{rel['toId']}"
|
|
569
|
-
status = client.query(project, "status")
|
|
570
|
-
projects.append((project, status.value["phase"]))
|
|
571
|
-
|
|
572
|
-
print(projects)
|
|
573
|
-
# Agent 2 learned which project Jane Smith is connected to without being told the project directly.
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
### Relationship Types
|
|
577
|
-
|
|
578
|
-
Relationship types are caller-defined strings. Common conventions:
|
|
579
|
-
|
|
580
|
-
| Relationship Type | Meaning |
|
|
581
|
-
|---|---|
|
|
582
|
-
| `MEMBER_OF` | Entity belongs to a team, lab, org, or group |
|
|
583
|
-
| `PART_OF` | Entity is a component or sub-unit of another entity |
|
|
584
|
-
| `AUTHORED` | Person or agent created a document, paper, or artifact |
|
|
585
|
-
| `LEADS` | Person, team, or org leads a project or effort |
|
|
586
|
-
| `DEPENDS_ON` | Project, service, or task depends on another entity |
|
|
587
|
-
| `REPORTS_TO` | Directed reporting relationship between people or agents |
|
|
588
|
-
|
|
589
|
-
Use uppercase snake case for consistency. Iranti does not enforce a fixed ontology here; the calling application owns the relationship vocabulary.
|
|
590
|
-
|
|
591
|
-
### Hybrid Search
|
|
592
|
-
|
|
593
|
-
```python
|
|
594
|
-
matches = client.search(
|
|
595
|
-
query="current blocker launch readiness",
|
|
596
|
-
entity_type="project",
|
|
597
|
-
limit=5,
|
|
598
|
-
lexical_weight=0.45,
|
|
599
|
-
vector_weight=0.55,
|
|
600
|
-
)
|
|
601
|
-
|
|
602
|
-
for item in matches:
|
|
603
|
-
print(item["entity"], item["key"], item["score"])
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
### Context Persistence (attend)
|
|
607
|
-
|
|
608
|
-
```python
|
|
609
|
-
# Before each LLM call, let Attendant decide if memory is needed
|
|
610
|
-
result = client.attend(
|
|
611
|
-
agent_id="research_agent_001",
|
|
612
|
-
latest_message="What's Jane Smith's current affiliation?",
|
|
613
|
-
current_context="User: What's Jane Smith's current affiliation?\nAssistant: Let me check...",
|
|
614
|
-
max_facts=5
|
|
615
|
-
)
|
|
616
|
-
|
|
617
|
-
if result["shouldInject"]:
|
|
618
|
-
for fact in result['facts']:
|
|
619
|
-
print(f"Inject: [{fact['entityKey']}] {fact['summary']}")
|
|
620
|
-
```
|
|
621
|
-
|
|
622
|
-
### Working Memory (handshake)
|
|
623
|
-
|
|
624
|
-
```python
|
|
625
|
-
# At session start, get personalized brief for agent's current task
|
|
438
|
+
iranti configure instance local --interactive
|
|
439
|
+
|
|
440
|
+
# Provider key shortcuts
|
|
441
|
+
iranti list api-keys --instance local
|
|
442
|
+
iranti add api-key openai --instance local
|
|
443
|
+
iranti update api-key claude --instance local
|
|
444
|
+
iranti remove api-key gemini --instance local
|
|
445
|
+
|
|
446
|
+
# Create a registry-backed API key and sync it into the instance env
|
|
447
|
+
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
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
`iranti add|update|remove api-key` updates the stored upstream provider credentials in the instance env without hand-editing `.env` files. `iranti list api-keys` shows which provider keys are currently stored. Supported remote providers are OpenAI, Claude, Gemini, Groq, and Mistral. `mock` and `ollama` do not require remote API keys, and Perplexity is not yet supported.
|
|
451
|
+
|
|
452
|
+
### 4) Run Iranti from that instance
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
iranti run --instance local
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
If a provider rejects requests because credits are exhausted, billing is disabled, or the account is quota-limited, Iranti now surfaces a direct message such as `OpenAI quota or billing limit reached. Add credits, update the API key, or switch providers.`
|
|
459
|
+
|
|
460
|
+
### 5) Bind any chatbot/app project to that instance
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
cd /path/to/your/chatbot
|
|
464
|
+
iranti project init . --instance local --agent-id chatbot_main
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
This writes `.env.iranti` in the project with the correct `IRANTI_URL`, `IRANTI_API_KEY`, and default agent identity.
|
|
468
|
+
|
|
469
|
+
Later changes use the same surface:
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
iranti configure project . --instance local --agent-id chatbot_worker
|
|
473
|
+
iranti configure project . --interactive
|
|
474
|
+
iranti auth create-key --instance local --key-id chatbot_worker --owner "Chatbot Worker" --scopes "kb:read,memory:read,memory:write" --project .
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
For multi-agent systems, bind once per project and set unique agent IDs per worker (for example `planner_agent`, `research_agent`, `critic_agent`).
|
|
478
|
+
|
|
479
|
+
### Installation Diagnostics
|
|
480
|
+
|
|
481
|
+
Use the CLI doctor command before first run or before a release check:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
iranti doctor
|
|
485
|
+
iranti doctor --instance local
|
|
486
|
+
iranti status
|
|
487
|
+
iranti upgrade --check
|
|
488
|
+
iranti upgrade --dry-run
|
|
489
|
+
iranti upgrade --yes
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
This validates the active env file, database URL, API key presence, provider selection, and provider-specific credentials.
|
|
493
|
+
`iranti status` shows the current runtime root, known instances, and local binding files.
|
|
494
|
+
`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`.
|
|
495
|
+
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.
|
|
496
|
+
`iranti configure ...` updates instance/project credentials without manual env editing.
|
|
497
|
+
`iranti auth ...` manages registry-backed API keys and can sync them into instance or project bindings.
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Core API
|
|
502
|
+
|
|
503
|
+
### Write a Fact
|
|
504
|
+
|
|
505
|
+
```python
|
|
506
|
+
from clients.python.iranti import IrantiClient
|
|
507
|
+
|
|
508
|
+
client = IrantiClient(
|
|
509
|
+
base_url="http://localhost:3001",
|
|
510
|
+
api_key="your_api_key_here"
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
result = client.write(
|
|
514
|
+
entity="researcher/jane_smith", # Format: entityType/entityId
|
|
515
|
+
key="affiliation",
|
|
516
|
+
value={"institution": "MIT", "department": "CSAIL"},
|
|
517
|
+
summary="Affiliated with MIT CSAIL", # Compressed for working memory
|
|
518
|
+
confidence=85, # 0-100
|
|
519
|
+
source="OpenAlex",
|
|
520
|
+
agent="research_agent_001"
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
print(result.action) # 'created', 'updated', 'escalated', or 'rejected'
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Query a Fact
|
|
527
|
+
|
|
528
|
+
```python
|
|
529
|
+
result = client.query("researcher/jane_smith", "affiliation")
|
|
530
|
+
|
|
531
|
+
if result.found:
|
|
532
|
+
print(result.value) # {"institution": "MIT", "department": "CSAIL"}
|
|
533
|
+
print(result.confidence) # 85
|
|
534
|
+
print(result.source) # "OpenAlex"
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Query All Facts for an Entity
|
|
538
|
+
|
|
539
|
+
```python
|
|
540
|
+
facts = client.query_all("researcher/jane_smith")
|
|
541
|
+
|
|
542
|
+
for fact in facts:
|
|
543
|
+
print(f"[{fact['key']}] {fact['summary']} (confidence: {fact['confidence']})")
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Graph Traversal
|
|
547
|
+
|
|
548
|
+
```python
|
|
549
|
+
from clients.python.iranti import IrantiClient
|
|
550
|
+
|
|
551
|
+
client = IrantiClient(base_url="http://localhost:3001", api_key="your_api_key_here")
|
|
552
|
+
|
|
553
|
+
# Agent 1 writes facts and links them into a graph.
|
|
554
|
+
client.write("researcher/jane_smith", "affiliation", {"lab": "CSAIL"}, "Jane Smith is affiliated with CSAIL", 90, "OpenAlex", "research_agent")
|
|
555
|
+
client.write("project/quantum_bridge", "status", {"phase": "active"}, "Quantum Bridge is active", 88, "project_brief", "research_agent")
|
|
556
|
+
|
|
557
|
+
client.relate("researcher/jane_smith", "MEMBER_OF", "lab/csail", created_by="research_agent")
|
|
558
|
+
client.relate("lab/csail", "LEADS", "project/quantum_bridge", created_by="research_agent")
|
|
559
|
+
|
|
560
|
+
# Agent 2 starts cold and traverses outward from Jane Smith.
|
|
561
|
+
one_hop = client.related("researcher/jane_smith")
|
|
562
|
+
labs = [f"{r['toType']}/{r['toId']}" for r in one_hop if r["relationshipType"] == "MEMBER_OF"]
|
|
563
|
+
|
|
564
|
+
projects = []
|
|
565
|
+
for lab in labs:
|
|
566
|
+
for rel in client.related(lab):
|
|
567
|
+
if rel["relationshipType"] == "LEADS":
|
|
568
|
+
project = f"{rel['toType']}/{rel['toId']}"
|
|
569
|
+
status = client.query(project, "status")
|
|
570
|
+
projects.append((project, status.value["phase"]))
|
|
571
|
+
|
|
572
|
+
print(projects)
|
|
573
|
+
# Agent 2 learned which project Jane Smith is connected to without being told the project directly.
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Relationship Types
|
|
577
|
+
|
|
578
|
+
Relationship types are caller-defined strings. Common conventions:
|
|
579
|
+
|
|
580
|
+
| Relationship Type | Meaning |
|
|
581
|
+
|---|---|
|
|
582
|
+
| `MEMBER_OF` | Entity belongs to a team, lab, org, or group |
|
|
583
|
+
| `PART_OF` | Entity is a component or sub-unit of another entity |
|
|
584
|
+
| `AUTHORED` | Person or agent created a document, paper, or artifact |
|
|
585
|
+
| `LEADS` | Person, team, or org leads a project or effort |
|
|
586
|
+
| `DEPENDS_ON` | Project, service, or task depends on another entity |
|
|
587
|
+
| `REPORTS_TO` | Directed reporting relationship between people or agents |
|
|
588
|
+
|
|
589
|
+
Use uppercase snake case for consistency. Iranti does not enforce a fixed ontology here; the calling application owns the relationship vocabulary.
|
|
590
|
+
|
|
591
|
+
### Hybrid Search
|
|
592
|
+
|
|
593
|
+
```python
|
|
594
|
+
matches = client.search(
|
|
595
|
+
query="current blocker launch readiness",
|
|
596
|
+
entity_type="project",
|
|
597
|
+
limit=5,
|
|
598
|
+
lexical_weight=0.45,
|
|
599
|
+
vector_weight=0.55,
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
for item in matches:
|
|
603
|
+
print(item["entity"], item["key"], item["score"])
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Context Persistence (attend)
|
|
607
|
+
|
|
608
|
+
```python
|
|
609
|
+
# Before each LLM call, let Attendant decide if memory is needed
|
|
610
|
+
result = client.attend(
|
|
611
|
+
agent_id="research_agent_001",
|
|
612
|
+
latest_message="What's Jane Smith's current affiliation?",
|
|
613
|
+
current_context="User: What's Jane Smith's current affiliation?\nAssistant: Let me check...",
|
|
614
|
+
max_facts=5
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
if result["shouldInject"]:
|
|
618
|
+
for fact in result['facts']:
|
|
619
|
+
print(f"Inject: [{fact['entityKey']}] {fact['summary']}")
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Working Memory (handshake)
|
|
623
|
+
|
|
624
|
+
```python
|
|
625
|
+
# At session start, get personalized brief for agent's current task
|
|
626
626
|
brief = client.handshake(
|
|
627
627
|
agent_id="research_agent_001",
|
|
628
628
|
task="Research publication history for Dr. Jane Smith",
|
|
629
629
|
recent_messages=["Starting literature review..."]
|
|
630
630
|
)
|
|
631
|
-
|
|
632
|
-
print(brief.operating_rules) # Staff namespace rules for this agent
|
|
633
|
-
print(brief.inferred_task_type) # e.g. "research", "verification"
|
|
634
|
-
|
|
635
|
-
for entry in brief.working_memory:
|
|
636
|
-
print(f"{entry.entity_key}: {entry.summary}")
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
---
|
|
640
|
-
|
|
641
|
-
## CrewAI Integration
|
|
642
|
-
|
|
643
|
-
Minimal working example based on validated experiments:
|
|
644
|
-
|
|
645
|
-
```python
|
|
646
|
-
from crewai import Agent, Task, Crew, LLM
|
|
647
|
-
from crewai.tools import tool
|
|
648
|
-
from clients.python.iranti import IrantiClient
|
|
649
|
-
|
|
650
|
-
iranti = IrantiClient(base_url="http://localhost:3001", api_key="your_key")
|
|
651
|
-
ENTITY = "project/my_project"
|
|
652
|
-
|
|
653
|
-
@tool("Write finding to shared memory")
|
|
654
|
-
def write_finding(key: str, value: str, summary: str, confidence: int) -> str:
|
|
655
|
-
"""Write a fact to Iranti so other agents can access it."""
|
|
656
|
-
result = iranti.write(
|
|
657
|
-
entity=ENTITY,
|
|
658
|
-
key=key,
|
|
659
|
-
value={"data": value},
|
|
660
|
-
summary=summary,
|
|
661
|
-
confidence=confidence,
|
|
662
|
-
source="briefing_doc",
|
|
663
|
-
agent="researcher_agent"
|
|
664
|
-
)
|
|
665
|
-
return f"Saved '{key}': {result.action}"
|
|
666
|
-
|
|
667
|
-
@tool("Get all findings")
|
|
668
|
-
def get_all_findings() -> str:
|
|
669
|
-
"""Load all facts from Iranti."""
|
|
670
|
-
facts = iranti.query_all(ENTITY)
|
|
671
|
-
if not facts:
|
|
672
|
-
return "No findings in shared memory."
|
|
673
|
-
lines = [f"[{f['key']}] {f['summary']} (confidence: {f['confidence']})" for f in facts]
|
|
674
|
-
return "\n".join(lines)
|
|
675
|
-
|
|
676
|
-
# Researcher agent: writes to Iranti
|
|
677
|
-
researcher = Agent(
|
|
678
|
-
role="Research Analyst",
|
|
679
|
-
goal="Extract facts from documents and save to shared memory",
|
|
680
|
-
tools=[write_finding],
|
|
681
|
-
llm=LLM(model="gpt-4o-mini")
|
|
682
|
-
)
|
|
683
|
-
|
|
684
|
-
# Analyst agent: reads from Iranti
|
|
685
|
-
analyst = Agent(
|
|
686
|
-
role="Project Analyst",
|
|
687
|
-
goal="Summarize projects using shared memory",
|
|
688
|
-
tools=[get_all_findings],
|
|
689
|
-
llm=LLM(model="gpt-4o-mini")
|
|
690
|
-
)
|
|
691
|
-
|
|
692
|
-
# Researcher extracts facts, analyst loads them — no direct communication needed
|
|
693
|
-
crew = Crew(agents=[researcher, analyst], tasks=[...])
|
|
694
|
-
crew.kickoff()
|
|
695
|
-
```
|
|
696
|
-
|
|
697
|
-
**Result**: Analyst successfully loads all facts written by researcher (validated 6/6 transfer rate).
|
|
698
|
-
|
|
699
|
-
---
|
|
700
|
-
|
|
701
|
-
## Middleware for Any LLM
|
|
702
|
-
|
|
703
|
-
Add Iranti memory to Claude, ChatGPT, or any LLM via API wrapper:
|
|
704
|
-
|
|
705
|
-
```python
|
|
706
|
-
from clients.middleware.iranti_middleware import IrantiMiddleware
|
|
707
|
-
|
|
708
|
-
middleware = IrantiMiddleware(
|
|
709
|
-
agent_id="my_agent",
|
|
710
|
-
iranti_url="http://localhost:3001"
|
|
711
|
-
)
|
|
712
|
-
|
|
713
|
-
# Before sending to LLM
|
|
714
|
-
augmented = middleware.before_send(
|
|
715
|
-
user_message="What was the blocker?",
|
|
716
|
-
conversation_history=[...]
|
|
717
|
-
)
|
|
718
|
-
|
|
719
|
-
# After receiving response
|
|
720
|
-
middleware.after_receive(
|
|
721
|
-
response="The blocker is...",
|
|
722
|
-
conversation_history=[...]
|
|
723
|
-
)
|
|
724
|
-
```
|
|
725
|
-
|
|
726
|
-
**How it works**:
|
|
727
|
-
1. `before_send()` calls `attend()` with conversation context
|
|
728
|
-
2. Forgotten facts are prepended as `[MEMORY: ...]`
|
|
729
|
-
3. `after_receive()` extracts new facts and saves them (best-effort)
|
|
730
|
-
|
|
731
|
-
**Note**: Browser extensions are blocked by ChatGPT and Claude's Content Security Policy. Use API-based middleware instead.
|
|
732
|
-
|
|
733
|
-
**Examples**: [`clients/middleware/claude_example.py`](clients/middleware/claude_example.py)
|
|
734
|
-
|
|
735
|
-
---
|
|
736
|
-
|
|
737
|
-
## Architecture
|
|
738
|
-
|
|
739
|
-
Iranti has five internal components:
|
|
740
|
-
|
|
741
|
-
| Component | Role |
|
|
742
|
-
|---|---|
|
|
743
|
-
| **Library** | PostgreSQL knowledge base. Current truth lives in `knowledge_base`; closed and contested intervals live in `archive`. |
|
|
744
|
-
| **Librarian** | Manages all writes. Detects conflicts, reasons about resolution, escalates when uncertain. |
|
|
745
|
-
| **Attendant** | Per-agent working memory manager. Implements `attend()`, `observe()`, and `handshake()` APIs. |
|
|
746
|
-
| **Archivist** | Periodic cleanup. Archives expired and low-confidence entries. Processes human-resolved conflicts. |
|
|
747
|
-
| **Resolutionist** | Interactive CLI helper that walks pending escalation files, writes `AUTHORITATIVE_JSON`, and marks them resolved for the Archivist. |
|
|
748
|
-
|
|
749
|
-
### REST API
|
|
750
|
-
|
|
751
|
-
Express server on port 3001 with endpoints:
|
|
752
|
-
|
|
753
|
-
- `POST /kb/write` - Write atomic fact
|
|
754
|
-
- `POST /kb/ingest` - Ingest raw text for one entity, auto-chunk into facts with per-fact confidence and per-fact write outcomes
|
|
755
|
-
- `GET /kb/query/:entityType/:entityId/:key` - Query specific fact
|
|
756
|
-
- `GET /kb/query/:entityType/:entityId` - Query all facts for entity
|
|
757
|
-
- `GET /kb/search` - Hybrid search across facts
|
|
631
|
+
|
|
632
|
+
print(brief.operating_rules) # Staff namespace rules for this agent
|
|
633
|
+
print(brief.inferred_task_type) # e.g. "research", "verification"
|
|
634
|
+
|
|
635
|
+
for entry in brief.working_memory:
|
|
636
|
+
print(f"{entry.entity_key}: {entry.summary}")
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
---
|
|
640
|
+
|
|
641
|
+
## CrewAI Integration
|
|
642
|
+
|
|
643
|
+
Minimal working example based on validated experiments:
|
|
644
|
+
|
|
645
|
+
```python
|
|
646
|
+
from crewai import Agent, Task, Crew, LLM
|
|
647
|
+
from crewai.tools import tool
|
|
648
|
+
from clients.python.iranti import IrantiClient
|
|
649
|
+
|
|
650
|
+
iranti = IrantiClient(base_url="http://localhost:3001", api_key="your_key")
|
|
651
|
+
ENTITY = "project/my_project"
|
|
652
|
+
|
|
653
|
+
@tool("Write finding to shared memory")
|
|
654
|
+
def write_finding(key: str, value: str, summary: str, confidence: int) -> str:
|
|
655
|
+
"""Write a fact to Iranti so other agents can access it."""
|
|
656
|
+
result = iranti.write(
|
|
657
|
+
entity=ENTITY,
|
|
658
|
+
key=key,
|
|
659
|
+
value={"data": value},
|
|
660
|
+
summary=summary,
|
|
661
|
+
confidence=confidence,
|
|
662
|
+
source="briefing_doc",
|
|
663
|
+
agent="researcher_agent"
|
|
664
|
+
)
|
|
665
|
+
return f"Saved '{key}': {result.action}"
|
|
666
|
+
|
|
667
|
+
@tool("Get all findings")
|
|
668
|
+
def get_all_findings() -> str:
|
|
669
|
+
"""Load all facts from Iranti."""
|
|
670
|
+
facts = iranti.query_all(ENTITY)
|
|
671
|
+
if not facts:
|
|
672
|
+
return "No findings in shared memory."
|
|
673
|
+
lines = [f"[{f['key']}] {f['summary']} (confidence: {f['confidence']})" for f in facts]
|
|
674
|
+
return "\n".join(lines)
|
|
675
|
+
|
|
676
|
+
# Researcher agent: writes to Iranti
|
|
677
|
+
researcher = Agent(
|
|
678
|
+
role="Research Analyst",
|
|
679
|
+
goal="Extract facts from documents and save to shared memory",
|
|
680
|
+
tools=[write_finding],
|
|
681
|
+
llm=LLM(model="gpt-4o-mini")
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
# Analyst agent: reads from Iranti
|
|
685
|
+
analyst = Agent(
|
|
686
|
+
role="Project Analyst",
|
|
687
|
+
goal="Summarize projects using shared memory",
|
|
688
|
+
tools=[get_all_findings],
|
|
689
|
+
llm=LLM(model="gpt-4o-mini")
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
# Researcher extracts facts, analyst loads them — no direct communication needed
|
|
693
|
+
crew = Crew(agents=[researcher, analyst], tasks=[...])
|
|
694
|
+
crew.kickoff()
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
**Result**: Analyst successfully loads all facts written by researcher (validated 6/6 transfer rate).
|
|
698
|
+
|
|
699
|
+
---
|
|
700
|
+
|
|
701
|
+
## Middleware for Any LLM
|
|
702
|
+
|
|
703
|
+
Add Iranti memory to Claude, ChatGPT, or any LLM via API wrapper:
|
|
704
|
+
|
|
705
|
+
```python
|
|
706
|
+
from clients.middleware.iranti_middleware import IrantiMiddleware
|
|
707
|
+
|
|
708
|
+
middleware = IrantiMiddleware(
|
|
709
|
+
agent_id="my_agent",
|
|
710
|
+
iranti_url="http://localhost:3001"
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
# Before sending to LLM
|
|
714
|
+
augmented = middleware.before_send(
|
|
715
|
+
user_message="What was the blocker?",
|
|
716
|
+
conversation_history=[...]
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
# After receiving response
|
|
720
|
+
middleware.after_receive(
|
|
721
|
+
response="The blocker is...",
|
|
722
|
+
conversation_history=[...]
|
|
723
|
+
)
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
**How it works**:
|
|
727
|
+
1. `before_send()` calls `attend()` with conversation context
|
|
728
|
+
2. Forgotten facts are prepended as `[MEMORY: ...]`
|
|
729
|
+
3. `after_receive()` extracts new facts and saves them (best-effort)
|
|
730
|
+
|
|
731
|
+
**Note**: Browser extensions are blocked by ChatGPT and Claude's Content Security Policy. Use API-based middleware instead.
|
|
732
|
+
|
|
733
|
+
**Examples**: [`clients/middleware/claude_example.py`](clients/middleware/claude_example.py)
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## Architecture
|
|
738
|
+
|
|
739
|
+
Iranti has five internal components:
|
|
740
|
+
|
|
741
|
+
| Component | Role |
|
|
742
|
+
|---|---|
|
|
743
|
+
| **Library** | PostgreSQL knowledge base. Current truth lives in `knowledge_base`; closed and contested intervals live in `archive`. |
|
|
744
|
+
| **Librarian** | Manages all writes. Detects conflicts, reasons about resolution, escalates when uncertain. |
|
|
745
|
+
| **Attendant** | Per-agent working memory manager. Implements `attend()`, `observe()`, and `handshake()` APIs. |
|
|
746
|
+
| **Archivist** | Periodic cleanup. Archives expired and low-confidence entries. Processes human-resolved conflicts. |
|
|
747
|
+
| **Resolutionist** | Interactive CLI helper that walks pending escalation files, writes `AUTHORITATIVE_JSON`, and marks them resolved for the Archivist. |
|
|
748
|
+
|
|
749
|
+
### REST API
|
|
750
|
+
|
|
751
|
+
Express server on port 3001 with endpoints:
|
|
752
|
+
|
|
753
|
+
- `POST /kb/write` - Write atomic fact
|
|
754
|
+
- `POST /kb/ingest` - Ingest raw text for one entity, auto-chunk into facts with per-fact confidence and per-fact write outcomes
|
|
755
|
+
- `GET /kb/query/:entityType/:entityId/:key` - Query specific fact
|
|
756
|
+
- `GET /kb/query/:entityType/:entityId` - Query all facts for entity
|
|
757
|
+
- `GET /kb/search` - Hybrid search across facts
|
|
758
758
|
- `POST /memory/attend` - Decide whether to inject memory for this turn
|
|
759
759
|
- `POST /memory/observe` - Context persistence (inject missing facts)
|
|
760
760
|
- `POST /memory/handshake` - Working memory brief for agent session
|
|
761
761
|
- `GET /memory/sessions` - List persisted operator-visible session checkpoints across agents, with optional operator filters/sorting
|
|
762
762
|
- `GET /memory/session/:agentId` - Inspect the current persisted session checkpoint/recovery state
|
|
763
763
|
- `POST /kb/relate` - Create entity relationship
|
|
764
|
-
- `GET /kb/related/:entityType/:entityId` - Get related entities
|
|
765
|
-
- `POST /agents/register` - Register agent in registry
|
|
766
|
-
|
|
767
|
-
All endpoints require `X-Iranti-Key` header for authentication.
|
|
768
|
-
|
|
769
|
-
---
|
|
770
|
-
|
|
771
|
-
## Schema
|
|
772
|
-
|
|
773
|
-
Six PostgreSQL tables:
|
|
774
|
-
|
|
775
|
-
```
|
|
776
|
-
knowledge_base - current truth (one live row per entity/key)
|
|
777
|
-
archive - temporal and provenance history for superseded, contradicted, escalated, and expired rows
|
|
778
|
-
entity_relationships - directional graph: MEMBER_OF, PART_OF, AUTHORED, etc.
|
|
779
|
-
entities - canonical entity identity registry
|
|
780
|
-
entity_aliases - normalized aliases mapped to canonical entities
|
|
781
|
-
write_receipts - idempotency receipts for requestId replay safety
|
|
782
|
-
```
|
|
783
|
-
|
|
784
|
-
New entity types, relationship types, and fact keys do not require migrations; they are caller-defined strings.
|
|
785
|
-
|
|
786
|
-
**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.
|
|
787
|
-
|
|
788
|
-
---
|
|
789
|
-
|
|
790
|
-
## Running Tests
|
|
791
|
-
|
|
792
|
-
```bash
|
|
793
|
-
npm run test:integration # Full end-to-end
|
|
794
|
-
npm run test:librarian # Conflict resolution
|
|
795
|
-
npm run test:attendant # Working memory
|
|
796
|
-
npm run test:reliability # Source scoring
|
|
797
|
-
|
|
798
|
-
# Python validation experiments
|
|
799
|
-
cd clients/experiments
|
|
800
|
-
python validate_nexus_observe.py # Context persistence
|
|
801
|
-
python validate_nexus_treatment.py # Cross-agent transfer
|
|
802
|
-
```
|
|
803
|
-
|
|
804
|
-
---
|
|
805
|
-
|
|
806
|
-
## Contributing
|
|
807
|
-
|
|
808
|
-
Contributions welcome! Please:
|
|
809
|
-
|
|
810
|
-
1. Fork the repository
|
|
811
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
812
|
-
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
813
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
814
|
-
5. Open a Pull Request
|
|
815
|
-
|
|
816
|
-
---
|
|
817
|
-
|
|
818
|
-
## License
|
|
819
|
-
|
|
820
|
-
GNU Affero General Public License v3.0 (AGPL-3.0) - see [LICENSE](LICENSE) file for details.
|
|
821
|
-
|
|
822
|
-
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.
|
|
823
|
-
|
|
824
|
-
---
|
|
825
|
-
|
|
826
|
-
## Name
|
|
827
|
-
|
|
828
|
-
Iranti is the Yoruba word for memory and remembrance.
|
|
829
|
-
|
|
830
|
-
---
|
|
831
|
-
|
|
832
|
-
## Project Structure
|
|
833
|
-
|
|
834
|
-
```
|
|
835
|
-
src/
|
|
836
|
-
├── library/ — DB client, queries, relationships, agent registry
|
|
837
|
-
├── librarian/ — Write logic, conflict resolution, reliability
|
|
838
|
-
├── attendant/ — Per-agent working memory, observe() implementation
|
|
839
|
-
├── archivist/ — Periodic cleanup, escalation processing
|
|
840
|
-
├── lib/ — LLM abstraction, model router, providers
|
|
841
|
-
├── sdk/ — Public TypeScript API
|
|
842
|
-
└── api/ — REST API server
|
|
843
|
-
|
|
844
|
-
clients/
|
|
845
|
-
├── python/ — Python client (IrantiClient)
|
|
846
|
-
├── middleware/ — LLM conversation wrappers (Claude, ChatGPT, etc.)
|
|
847
|
-
└── experiments/ — Validated experiments with real results
|
|
848
|
-
|
|
849
|
-
docs/
|
|
850
|
-
└── internal/validation_results.md — Full experiment outputs and analysis
|
|
851
|
-
```
|
|
852
|
-
|
|
853
|
-
---
|
|
854
|
-
|
|
855
|
-
## Support
|
|
856
|
-
|
|
857
|
-
- **Issues**: [GitHub Issues](https://github.com/nfemmanuel/iranti/issues)
|
|
858
|
-
- **Discussions**: [GitHub Discussions](https://github.com/nfemmanuel/iranti/discussions)
|
|
859
|
-
- **Email**: oluwaniifemi.emmanuel@uni.minerva.edu
|
|
860
|
-
- **Changelog**: [`CHANGELOG.md`](CHANGELOG.md)
|
|
861
|
-
|
|
862
|
-
---
|
|
863
|
-
|
|
864
|
-
**Built with ❤️ for the multi-agent AI community.**
|
|
865
|
-
|
|
764
|
+
- `GET /kb/related/:entityType/:entityId` - Get related entities
|
|
765
|
+
- `POST /agents/register` - Register agent in registry
|
|
766
|
+
|
|
767
|
+
All endpoints require `X-Iranti-Key` header for authentication.
|
|
768
|
+
|
|
769
|
+
---
|
|
770
|
+
|
|
771
|
+
## Schema
|
|
772
|
+
|
|
773
|
+
Six PostgreSQL tables:
|
|
774
|
+
|
|
775
|
+
```
|
|
776
|
+
knowledge_base - current truth (one live row per entity/key)
|
|
777
|
+
archive - temporal and provenance history for superseded, contradicted, escalated, and expired rows
|
|
778
|
+
entity_relationships - directional graph: MEMBER_OF, PART_OF, AUTHORED, etc.
|
|
779
|
+
entities - canonical entity identity registry
|
|
780
|
+
entity_aliases - normalized aliases mapped to canonical entities
|
|
781
|
+
write_receipts - idempotency receipts for requestId replay safety
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
New entity types, relationship types, and fact keys do not require migrations; they are caller-defined strings.
|
|
785
|
+
|
|
786
|
+
**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.
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
790
|
+
## Running Tests
|
|
791
|
+
|
|
792
|
+
```bash
|
|
793
|
+
npm run test:integration # Full end-to-end
|
|
794
|
+
npm run test:librarian # Conflict resolution
|
|
795
|
+
npm run test:attendant # Working memory
|
|
796
|
+
npm run test:reliability # Source scoring
|
|
797
|
+
|
|
798
|
+
# Python validation experiments
|
|
799
|
+
cd clients/experiments
|
|
800
|
+
python validate_nexus_observe.py # Context persistence
|
|
801
|
+
python validate_nexus_treatment.py # Cross-agent transfer
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
---
|
|
805
|
+
|
|
806
|
+
## Contributing
|
|
807
|
+
|
|
808
|
+
Contributions welcome! Please:
|
|
809
|
+
|
|
810
|
+
1. Fork the repository
|
|
811
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
812
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
813
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
814
|
+
5. Open a Pull Request
|
|
815
|
+
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
## License
|
|
819
|
+
|
|
820
|
+
GNU Affero General Public License v3.0 (AGPL-3.0) - see [LICENSE](LICENSE) file for details.
|
|
821
|
+
|
|
822
|
+
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.
|
|
823
|
+
|
|
824
|
+
---
|
|
825
|
+
|
|
826
|
+
## Name
|
|
827
|
+
|
|
828
|
+
Iranti is the Yoruba word for memory and remembrance.
|
|
829
|
+
|
|
830
|
+
---
|
|
831
|
+
|
|
832
|
+
## Project Structure
|
|
833
|
+
|
|
834
|
+
```
|
|
835
|
+
src/
|
|
836
|
+
├── library/ — DB client, queries, relationships, agent registry
|
|
837
|
+
├── librarian/ — Write logic, conflict resolution, reliability
|
|
838
|
+
├── attendant/ — Per-agent working memory, observe() implementation
|
|
839
|
+
├── archivist/ — Periodic cleanup, escalation processing
|
|
840
|
+
├── lib/ — LLM abstraction, model router, providers
|
|
841
|
+
├── sdk/ — Public TypeScript API
|
|
842
|
+
└── api/ — REST API server
|
|
843
|
+
|
|
844
|
+
clients/
|
|
845
|
+
├── python/ — Python client (IrantiClient)
|
|
846
|
+
├── middleware/ — LLM conversation wrappers (Claude, ChatGPT, etc.)
|
|
847
|
+
└── experiments/ — Validated experiments with real results
|
|
848
|
+
|
|
849
|
+
docs/
|
|
850
|
+
└── internal/validation_results.md — Full experiment outputs and analysis
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
---
|
|
854
|
+
|
|
855
|
+
## Support
|
|
856
|
+
|
|
857
|
+
- **Issues**: [GitHub Issues](https://github.com/nfemmanuel/iranti/issues)
|
|
858
|
+
- **Discussions**: [GitHub Discussions](https://github.com/nfemmanuel/iranti/discussions)
|
|
859
|
+
- **Email**: oluwaniifemi.emmanuel@uni.minerva.edu
|
|
860
|
+
- **Changelog**: [`CHANGELOG.md`](CHANGELOG.md)
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
**Built with ❤️ for the multi-agent AI community.**
|
|
865
|
+
|