@agxnte/reidx 2.0.2

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.
Files changed (135) hide show
  1. package/README.md +724 -0
  2. package/bin/reidx.js +33 -0
  3. package/package.json +40 -0
  4. package/pyproject.toml +45 -0
  5. package/scripts/find-python.js +24 -0
  6. package/scripts/postinstall.js +35 -0
  7. package/src/reidx/__init__.py +3 -0
  8. package/src/reidx/__main__.py +9 -0
  9. package/src/reidx/__pycache__/__init__.cpython-312.pyc +0 -0
  10. package/src/reidx/app/__init__.py +3 -0
  11. package/src/reidx/app/__pycache__/__init__.cpython-312.pyc +0 -0
  12. package/src/reidx/app/__pycache__/commands.cpython-312.pyc +0 -0
  13. package/src/reidx/app/commands.py +221 -0
  14. package/src/reidx/automation/__init__.py +3 -0
  15. package/src/reidx/automation/__pycache__/__init__.cpython-312.pyc +0 -0
  16. package/src/reidx/automation/__pycache__/exec.cpython-312.pyc +0 -0
  17. package/src/reidx/automation/exec.py +35 -0
  18. package/src/reidx/config/__init__.py +10 -0
  19. package/src/reidx/config/__pycache__/__init__.cpython-312.pyc +0 -0
  20. package/src/reidx/config/__pycache__/loader.cpython-312.pyc +0 -0
  21. package/src/reidx/config/__pycache__/models.cpython-312.pyc +0 -0
  22. package/src/reidx/config/__pycache__/settings.cpython-312.pyc +0 -0
  23. package/src/reidx/config/loader.py +104 -0
  24. package/src/reidx/config/models.py +49 -0
  25. package/src/reidx/config/settings.py +127 -0
  26. package/src/reidx/deepreid/__init__.py +8 -0
  27. package/src/reidx/deepreid/__pycache__/__init__.cpython-312.pyc +0 -0
  28. package/src/reidx/deepreid/__pycache__/pipeline.cpython-312.pyc +0 -0
  29. package/src/reidx/deepreid/pipeline.py +221 -0
  30. package/src/reidx/diagnostics/__init__.py +0 -0
  31. package/src/reidx/diagnostics/__pycache__/__init__.cpython-312.pyc +0 -0
  32. package/src/reidx/diagnostics/__pycache__/logger.cpython-312.pyc +0 -0
  33. package/src/reidx/diagnostics/logger.py +56 -0
  34. package/src/reidx/goals/__init__.py +21 -0
  35. package/src/reidx/goals/__pycache__/__init__.cpython-312.pyc +0 -0
  36. package/src/reidx/goals/__pycache__/models.cpython-312.pyc +0 -0
  37. package/src/reidx/goals/__pycache__/store.cpython-312.pyc +0 -0
  38. package/src/reidx/goals/models.py +101 -0
  39. package/src/reidx/goals/store.py +233 -0
  40. package/src/reidx/integrations/__init__.py +3 -0
  41. package/src/reidx/integrations/mcp.py +70 -0
  42. package/src/reidx/nyx/__init__.py +3 -0
  43. package/src/reidx/nyx/__pycache__/__init__.cpython-312.pyc +0 -0
  44. package/src/reidx/nyx/__pycache__/persona.cpython-312.pyc +0 -0
  45. package/src/reidx/nyx/persona.py +35 -0
  46. package/src/reidx/policy/__init__.py +15 -0
  47. package/src/reidx/policy/__pycache__/__init__.cpython-312.pyc +0 -0
  48. package/src/reidx/policy/__pycache__/engine.cpython-312.pyc +0 -0
  49. package/src/reidx/policy/__pycache__/models.cpython-312.pyc +0 -0
  50. package/src/reidx/policy/engine.py +101 -0
  51. package/src/reidx/policy/models.py +35 -0
  52. package/src/reidx/provider/__init__.py +16 -0
  53. package/src/reidx/provider/__pycache__/__init__.cpython-312.pyc +0 -0
  54. package/src/reidx/provider/__pycache__/_http.cpython-312.pyc +0 -0
  55. package/src/reidx/provider/__pycache__/anthropic.cpython-312.pyc +0 -0
  56. package/src/reidx/provider/__pycache__/base.cpython-312.pyc +0 -0
  57. package/src/reidx/provider/__pycache__/ollama.cpython-312.pyc +0 -0
  58. package/src/reidx/provider/__pycache__/openai.cpython-312.pyc +0 -0
  59. package/src/reidx/provider/__pycache__/registry.cpython-312.pyc +0 -0
  60. package/src/reidx/provider/__pycache__/store.cpython-312.pyc +0 -0
  61. package/src/reidx/provider/__pycache__/stub.cpython-312.pyc +0 -0
  62. package/src/reidx/provider/_http.py +29 -0
  63. package/src/reidx/provider/anthropic.py +176 -0
  64. package/src/reidx/provider/base.py +50 -0
  65. package/src/reidx/provider/ollama.py +109 -0
  66. package/src/reidx/provider/openai.py +144 -0
  67. package/src/reidx/provider/registry.py +88 -0
  68. package/src/reidx/provider/store.py +141 -0
  69. package/src/reidx/provider/stub.py +60 -0
  70. package/src/reidx/provider_manager/__init__.py +40 -0
  71. package/src/reidx/provider_manager/__pycache__/__init__.cpython-312.pyc +0 -0
  72. package/src/reidx/provider_manager/__pycache__/catalog.cpython-312.pyc +0 -0
  73. package/src/reidx/provider_manager/__pycache__/database.cpython-312.pyc +0 -0
  74. package/src/reidx/provider_manager/__pycache__/keychain.cpython-312.pyc +0 -0
  75. package/src/reidx/provider_manager/__pycache__/palette.cpython-312.pyc +0 -0
  76. package/src/reidx/provider_manager/catalog.py +330 -0
  77. package/src/reidx/provider_manager/database.py +234 -0
  78. package/src/reidx/provider_manager/keychain.py +102 -0
  79. package/src/reidx/provider_manager/palette.py +831 -0
  80. package/src/reidx/runtime/__init__.py +5 -0
  81. package/src/reidx/runtime/__pycache__/__init__.cpython-312.pyc +0 -0
  82. package/src/reidx/runtime/__pycache__/agent.cpython-312.pyc +0 -0
  83. package/src/reidx/runtime/__pycache__/orchestrator.cpython-312.pyc +0 -0
  84. package/src/reidx/runtime/__pycache__/reasoning.cpython-312.pyc +0 -0
  85. package/src/reidx/runtime/__pycache__/state.cpython-312.pyc +0 -0
  86. package/src/reidx/runtime/__pycache__/subagent.cpython-312.pyc +0 -0
  87. package/src/reidx/runtime/agent.py +198 -0
  88. package/src/reidx/runtime/orchestrator.py +244 -0
  89. package/src/reidx/runtime/reasoning.py +77 -0
  90. package/src/reidx/runtime/state.py +32 -0
  91. package/src/reidx/runtime/subagent.py +174 -0
  92. package/src/reidx/session/__init__.py +4 -0
  93. package/src/reidx/session/__pycache__/__init__.cpython-312.pyc +0 -0
  94. package/src/reidx/session/__pycache__/models.cpython-312.pyc +0 -0
  95. package/src/reidx/session/__pycache__/store.cpython-312.pyc +0 -0
  96. package/src/reidx/session/models.py +43 -0
  97. package/src/reidx/session/store.py +101 -0
  98. package/src/reidx/tasks/__init__.py +4 -0
  99. package/src/reidx/tasks/__pycache__/__init__.cpython-312.pyc +0 -0
  100. package/src/reidx/tasks/__pycache__/models.cpython-312.pyc +0 -0
  101. package/src/reidx/tasks/__pycache__/store.cpython-312.pyc +0 -0
  102. package/src/reidx/tasks/models.py +44 -0
  103. package/src/reidx/tasks/store.py +86 -0
  104. package/src/reidx/tools/__init__.py +44 -0
  105. package/src/reidx/tools/__pycache__/__init__.cpython-312.pyc +0 -0
  106. package/src/reidx/tools/__pycache__/base.cpython-312.pyc +0 -0
  107. package/src/reidx/tools/__pycache__/file_tools.cpython-312.pyc +0 -0
  108. package/src/reidx/tools/__pycache__/registry.cpython-312.pyc +0 -0
  109. package/src/reidx/tools/__pycache__/shell_tool.cpython-312.pyc +0 -0
  110. package/src/reidx/tools/__pycache__/spawn_agent.cpython-312.pyc +0 -0
  111. package/src/reidx/tools/__pycache__/web_tools.cpython-312.pyc +0 -0
  112. package/src/reidx/tools/base.py +84 -0
  113. package/src/reidx/tools/file_tools.py +222 -0
  114. package/src/reidx/tools/registry.py +45 -0
  115. package/src/reidx/tools/shell_tool.py +75 -0
  116. package/src/reidx/tools/spawn_agent.py +185 -0
  117. package/src/reidx/tools/web_tools.py +216 -0
  118. package/src/reidx/ui/__init__.py +41 -0
  119. package/src/reidx/ui/__pycache__/__init__.cpython-312.pyc +0 -0
  120. package/src/reidx/ui/__pycache__/app.cpython-312.pyc +0 -0
  121. package/src/reidx/ui/__pycache__/commands.cpython-312.pyc +0 -0
  122. package/src/reidx/ui/__pycache__/render.cpython-312.pyc +0 -0
  123. package/src/reidx/ui/__pycache__/repl.cpython-312.pyc +0 -0
  124. package/src/reidx/ui/__pycache__/theme.cpython-312.pyc +0 -0
  125. package/src/reidx/ui/app.py +1343 -0
  126. package/src/reidx/ui/commands.py +663 -0
  127. package/src/reidx/ui/render.py +517 -0
  128. package/src/reidx/ui/repl.py +14 -0
  129. package/src/reidx/ui/theme.py +126 -0
  130. package/src/reidx/workflows/__init__.py +4 -0
  131. package/src/reidx/workflows/__pycache__/__init__.cpython-312.pyc +0 -0
  132. package/src/reidx/workflows/__pycache__/models.cpython-312.pyc +0 -0
  133. package/src/reidx/workflows/__pycache__/store.cpython-312.pyc +0 -0
  134. package/src/reidx/workflows/models.py +19 -0
  135. package/src/reidx/workflows/store.py +56 -0
package/README.md ADDED
@@ -0,0 +1,724 @@
1
+ # ReidX
2
+
3
+ Terminal-native personal intelligence and coding CLI with an agent-first runtime.
4
+
5
+ A real runtime — not a chat wrapper. Sessions, tasks, tools, policy gates,
6
+ providers, and persistence are first-class. A genuine full-screen TUI (not an
7
+ inline redraw hack) with a locked-to-bottom footer, scrollable history,
8
+ collapsible reasoning/tool-call output, a live subagent panel, and a live "/"
9
+ command menu. Built to grow into a durable operator surface.
10
+
11
+ **Status:** Phase 5 complete (correctness fixes + real resume + interaction
12
+ upgrade), plus a full-screen TUI rewrite, real HTTP providers (Anthropic /
13
+ OpenAI / OpenAI-compatible / Ollama), subagent spawning, DeepReid
14
+ (Researcher→Planner→Critic planning pipeline), Nyx (redteam persona mode),
15
+ web search, and workflows on top. See `docs/` for the architecture audit and
16
+ phase plans.
17
+
18
+ ---
19
+
20
+ ## Target stack
21
+
22
+ - **Python** 3.12+
23
+ - **Typer** — CLI command surface
24
+ - **Pydantic v2** — schemas and validation
25
+ - **Rich** — terminal rendering (markdown, tables, panels)
26
+ - **prompt_toolkit** — the full-screen TUI (layout, input, completion, mouse)
27
+ - No HTTP client dependency — the Anthropic/OpenAI/Ollama providers and
28
+ `web_search` all speak stdlib `urllib`, so there's nothing extra to install
29
+ to go from the offline stub to a real model.
30
+
31
+ ---
32
+
33
+ ## Quick start
34
+
35
+ ### Option A: install via npm
36
+
37
+ Requires Python 3.12+ on your `PATH` (the npm package is a thin wrapper that
38
+ pip-installs the Python package on `npm install`).
39
+
40
+ ```powershell
41
+ npm install -g reidx
42
+ ```
43
+
44
+ This gives you `reid` on your `PATH`. Skip to
45
+ [step 2](#2-verify-the-install) to check it worked.
46
+
47
+ ### Option B: install from source
48
+
49
+ #### 1. Create a venv and install
50
+
51
+ ```powershell
52
+ python -m venv .venv
53
+ .\.venv\Scripts\Activate.ps1
54
+ pip install -e ".[dev]"
55
+ ```
56
+
57
+ > On macOS/Linux: `source .venv/bin/activate` instead of the PowerShell line.
58
+
59
+ ### 2. Verify the install
60
+
61
+ ```powershell
62
+ reid doctor
63
+ ```
64
+
65
+ Expected output:
66
+
67
+ ```
68
+ reid 2.0.2
69
+ settings <path> (found|missing)
70
+ python <path> (3.13.x)
71
+ workspace <cwd>
72
+ storage ~/.reidx
73
+ provider stub
74
+ mode balanced
75
+ providers stub (active), N tools
76
+ anthropic not configured (env: ANTHROPIC_API_KEY)
77
+ ok runtime importable; provider available
78
+ ```
79
+
80
+ ### 3. Run it
81
+
82
+ ```powershell
83
+ reid
84
+ ```
85
+
86
+ Drops you into the interactive TUI with a fresh session. Type `/` to see every
87
+ available command with descriptions, or just start talking. The stub provider
88
+ is offline and exercisable without API keys.
89
+
90
+ ---
91
+
92
+ ## The interactive TUI
93
+
94
+ `reid` (with no subcommand, or `reid interactive`) launches a real
95
+ full-screen `prompt_toolkit` application — the same style of terminal
96
+ ownership as `vim`/`htop` (alternate screen; your native scrollback is
97
+ untouched and restored exactly as it was on exit). Rich handles all the
98
+ actual rendering (markdown, tables, panels); prompt_toolkit owns the screen,
99
+ input, and layout around it.
100
+
101
+ - **Locked-to-bottom footer** — a spinner row, the input box, an optional
102
+ subagent panel, and a status line (app name · mode · model · effort ·
103
+ token/context-window usage · workspace · task count) are always pinned to
104
+ the terminal's actual last rows. The scrollable output pane fills
105
+ everything above it.
106
+ - **Mouse-wheel scroll** — scroll up to read history without losing your
107
+ place; new replies keep arriving below the fold instead of yanking you back
108
+ down. Scroll back to the bottom (or far enough) and it re-locks
109
+ automatically. (Hold **Shift** while click-dragging for native text
110
+ selection/copy — mouse support for scrolling means the terminal hands mouse
111
+ events to the app, and Shift is the standard bypass every terminal supports
112
+ for that.)
113
+ - **Collapsible reasoning + tool calls (Ctrl+O)** — chain-of-thought shows as
114
+ a grayed-out `✻ Thought for Ns` line and each tool call as a one-line
115
+ `● tool(args) ok/error` summary, collapsed by default. `Ctrl+O` toggles
116
+ every collapsed block open at once to see the full detail.
117
+ - **`/` completion menu** — type `/` for a live menu of every slash command
118
+ with its description (Tab/↓/↑ to navigate, Enter to accept); no need to run
119
+ `/help` first, though `/help` still works and shows the same list grouped
120
+ by category.
121
+ - **Large/multi-line pastes collapse** to a placeholder like
122
+ `[Pasted text #1 +42 lines]` (same idea as Claude Code's own input box) —
123
+ the full text is still sent when you submit, only the box display is
124
+ compact.
125
+ - **Escape to stop a response** — while a reply is generating, `Esc` cancels
126
+ just that turn (the spinner switches to `◐ stopping…`) and returns whatever
127
+ partial answer/tool results it already had; the session itself stays open.
128
+ It's polled at safe points (before the next model call, between tool
129
+ calls), so it can't kill a request already in flight, but it ends the turn
130
+ at the next opportunity instead of waiting for it to run to completion.
131
+ `Ctrl+D` is still the one that exits the whole session.
132
+ - **Live subagent panel** — appears under the input box whenever the model
133
+ calls `spawn_agent` (see Tools below), showing one row per child agent:
134
+ name, status (running/done/error), elapsed time, and its last action.
135
+ Finished rows linger for ~2s then disappear; auto-hidden when nothing's
136
+ running.
137
+ - **DeepReid trigger** — type `deepread`/`deep reid` (a few spellings
138
+ accepted) at the very start of the box: it pulses green, and your message
139
+ runs through the real Researcher→Planner→Critic pipeline instead of a
140
+ normal turn. See "DeepReid" under Tools/What works now below.
141
+ - **Nyx mode** — `/nyx on` swaps the assistant's persona to a redteam/
142
+ offensive-security assistant for authorized pentesting and CTF work,
143
+ without changing what tools it can call or how the policy engine gates
144
+ them. See "Nyx (redteam mode)" below.
145
+ - **Keyboard shortcuts in the input box:**
146
+ - `↑` / `↓` — input history
147
+ - `←` / `→` — cycle reasoning effort (`low → medium → high → xhigh`) when
148
+ the box is empty; otherwise they move the cursor normally
149
+ - `Ctrl+O` — toggle collapsed/expanded reasoning + tool calls
150
+ - `Esc` — stop the in-flight response (only while one is generating)
151
+ - `Ctrl+C` — clear the current line; `Ctrl+D` — exit
152
+ - A small mascot renders next to the welcome banner on launch
153
+ (`render.py::banner`/`_MASCOT`) — purely cosmetic, easy to swap out.
154
+
155
+ ---
156
+
157
+ ## Command surface
158
+
159
+ ### Top-level CLI commands
160
+
161
+ | Command | Purpose |
162
+ |---|---|
163
+ | `reid` | Launch the interactive TUI (default — no subcommand needed) |
164
+ | `reid interactive "<prompt>"` | Launch interactive mode and immediately submit `<prompt>` as the first turn — session stays open afterward |
165
+ | `reid --file <path>` / `-f` | Same idea, but read the initial prompt from a text file — works with `interactive`, `exec`, and the bare/no-subcommand form |
166
+ | `reid --nyx` | Launch with the Nyx redteam/offensive-security persona active from the start (also on `interactive` and `exec`) |
167
+ | `<cmd> \| reid` | Pipe a prompt via stdin as the initial turn (only applies to the bare/no-subcommand form) |
168
+ | `reid exec "<prompt>"` | Run a single prompt non-interactively (headless) |
169
+ | `reid deepreid "<task>"` | Plan + review `<task>` via the Researcher/Planner/Critic pipeline (headless, like `exec`) — no code changes, saves a Markdown plan |
170
+ | `reid resume <session-id>` | Resume a prior session, then enter interactive mode |
171
+ | `reid sessions` | List all sessions |
172
+ | `reid config-show` | Show the effective (merged) configuration |
173
+ | `reid tools` | List registered tools with risk levels |
174
+ | `reid doctor` | Run environment diagnostics |
175
+ | `reid version` | Show version and runtime info |
176
+ | `reid --help` | Show the command surface |
177
+
178
+ ### Slash commands (inside the TUI)
179
+
180
+ Type `/` in the input box for a live completion menu of all of these with
181
+ descriptions — the table below is the same information, grouped.
182
+
183
+ **Session**
184
+
185
+ | Command | Purpose |
186
+ |---|---|
187
+ | `/status` | Show current session, mode, model, task count, workspace |
188
+ | `/sessions` | List all sessions with freshness |
189
+ | `/resume <id>` | Resume a prior session (restores message history) |
190
+ | `/transcript [n]` | Show last n messages (default 20) |
191
+ | `/rewind` | Drop the last turn from state |
192
+
193
+ **Tasks**
194
+
195
+ | Command | Purpose |
196
+ |---|---|
197
+ | `/tasks [status]` | List tasks; filter by `pending` `active` `completed` `failed` `blocked` `skipped` |
198
+
199
+ **Goals**
200
+
201
+ | Command | Purpose |
202
+ |---|---|
203
+ | `/goal` / `/goal show [id]` | Show the active goal, or a goal by id |
204
+ | `/goal <title>` | Create and activate a goal from free text |
205
+ | `/goal new <title>` | Create and activate a structured session goal |
206
+ | `/goal outcome <text>` | Set the active goal's success outcome |
207
+ | `/goal evidence add <text>` | Add observable success evidence |
208
+ | `/goal evidence done <index> [note]` | Mark evidence satisfied |
209
+ | `/goal add <title>` | Add a child subgoal |
210
+ | `/goal milestone <title>` | Add a milestone |
211
+ | `/goal list` | List session goals |
212
+ | `/goal active <id\|clear>` | Switch or clear the active goal |
213
+ | `/goal done [id] [note]` | Mark a goal or goal node completed |
214
+ | `/goal block [id] <reason>` | Mark a goal or goal node blocked |
215
+ | `/goal revise <note>` | Record a revision note |
216
+ | `/goal abandon [id] <reason>` | Abandon a goal or goal node |
217
+ | `/goal delete <id>` | Delete a goal |
218
+
219
+ How `/goal` works:
220
+
221
+ - A **goal** is the durable outcome you are trying to reach in the current
222
+ session. It is not the same thing as a task.
223
+ - A **task** is still one agent turn in `tasks.json`; a **goal** lives in
224
+ `goals.json` and tracks the larger outcome behind those turns.
225
+ - The **active goal** is the goal new tasks are linked to automatically. Use
226
+ `/goal active <id>` to switch it, or `/goal active clear` to stop linking
227
+ new tasks.
228
+ - `outcome` is the success condition in plain language.
229
+ - `evidence` is what would prove the goal is done. `/goal done` refuses to
230
+ complete a goal with no evidence, so the feature nudges you away from vague
231
+ activity tracking.
232
+ - `add` creates child subgoals. `milestone` creates progress markers. `block`,
233
+ `revise`, and `abandon` keep the history honest when reality changes.
234
+ - Free text is accepted as a shortcut for creating a new active goal, so
235
+ `/goal make me a report of ReidX` is the same kind of action as
236
+ `/goal new make me a report of ReidX`.
237
+
238
+ Typical flow:
239
+
240
+ ```text
241
+ /goal make me a report of ReidX
242
+ /goal outcome A useful report exists and cites the relevant code/docs
243
+ /goal evidence add Report covers command surface, runtime, tools, and persistence
244
+ /goal add Inspect README and docs
245
+ /goal milestone Draft report outline
246
+ /goal show
247
+ ```
248
+
249
+ After that, normal prompts you send in the TUI become tasks linked to the
250
+ active goal. Use `/tasks` to inspect execution history and `/goal show` to
251
+ inspect the goal hierarchy, evidence, blockers, and revisions.
252
+
253
+ **Config & Policy**
254
+
255
+ | Command | Purpose |
256
+ |---|---|
257
+ | `/model <name>` | Set the model for the session |
258
+ | `/effort <level>` | Set reasoning effort: `low` `medium` `high` `xhigh` |
259
+ | `/mode <mode>` | Set permission mode: `strict` `balanced` `autonomous` `custom` |
260
+ | `/nyx [on\|off]` | Toggle the Nyx redteam/offensive-security persona for this session (no args shows current state) |
261
+ | `/permissions` | Show current policy: mode, blocked/allowed commands, writable roots, timeouts |
262
+ | `/tools` | List registered tools with risk-level badges |
263
+
264
+ **Workflows**
265
+
266
+ | Command | Purpose |
267
+ |---|---|
268
+ | `/workflows` | List saved workflows |
269
+ | `/workflow save <name> [n]` | Save the last `n` user turns as a reusable workflow (default 5) |
270
+ | `/workflow show <name>` | Show a workflow's steps |
271
+ | `/workflow run <name>` | Run a workflow's steps in sequence — each step gets the same handling as typing it directly (slash commands and prompts both work, spinner/approval included) |
272
+ | `/workflow delete <name>` | Delete a workflow |
273
+
274
+ Workflows are global (not tied to a session or workspace) and persist to
275
+ `~/.reidx/workflows.json`, so a workflow saved in one session is runnable
276
+ from any other.
277
+
278
+ **Providers**
279
+
280
+ | Command | Purpose |
281
+ |---|---|
282
+ | `/providers` | List registered providers (persisted + auto-registered), showing which is active |
283
+ | `/connect <name> <kind> <base_url> [api_key] [model]` | Add a provider (`kind`: `anthropic` `openai` `openai-compatible` `ollama`); persists to disk |
284
+ | `/disconnect <name>` | Remove a saved provider (not the active one, not the built-ins) |
285
+ | `/use <name>` | Switch this session to a registered provider |
286
+
287
+ **Meta**
288
+
289
+ | Command | Purpose |
290
+ |---|---|
291
+ | `/help` | Show grouped help |
292
+ | `/clear` | Clear the output pane |
293
+ | `/exit` | Quit ReidX (also `Ctrl+D`; `Ctrl+C` clears the current input line) |
294
+
295
+ ---
296
+
297
+ ## Providers
298
+
299
+ `stub` (offline, deterministic) is always registered and always the default —
300
+ nothing auto-promotes over it. Real HTTP providers all speak stdlib `urllib`
301
+ (no extra dependency):
302
+
303
+ | Kind | Notes |
304
+ |---|---|
305
+ | `anthropic` | Anthropic Messages API (`/v1/messages`); also works against Anthropic-compatible proxies via `base_url` |
306
+ | `openai` | OpenAI-compatible chat completions API |
307
+ | `openai-compatible` | Same wire format as `openai`, for arbitrary self-hosted/compatible endpoints |
308
+ | `ollama` | Local Ollama server |
309
+
310
+ Two ways to get a real provider registered:
311
+
312
+ 1. **Env vars** (Anthropic only, auto-registered at startup, never made
313
+ default): `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_MODEL`.
314
+ 2. **`/connect`** — persists a `ProviderRecord` to
315
+ `<storage_root>/providers.json` (chmod `600` on POSIX) and registers it
316
+ immediately:
317
+
318
+ ```
319
+ /connect anthropic anthropic "" sk-ant-... claude-sonnet-5
320
+ /connect local ollama http://localhost:11434 "" llama3
321
+ /use local
322
+ ```
323
+
324
+ `/use` is session-scoped: it rebuilds the agent against the new provider but
325
+ never changes `config.default_provider`, so `stub` is still what a fresh
326
+ session starts on until you `/use` again. `/disconnect` refuses to remove the
327
+ active provider or either built-in name (`stub`, `anthropic`).
328
+
329
+ `spawn_agent` (see Tools below) inherits the parent's active provider by
330
+ default, so switching to a local model at the top level applies to child
331
+ agents too — it can also be given a one-off `provider`/`model` override.
332
+
333
+ ---
334
+
335
+ ## Nyx (redteam mode)
336
+
337
+ Nyx swaps the assistant's system prompt to a redteam/offensive-security
338
+ persona for authorized penetration testing, CTF competitions, and security
339
+ research — recon, exploit development, payload construction, privilege
340
+ escalation, C2 usage, and report writing, described directly rather than with
341
+ vague hedging. It still pushes back on requests with no stated engagement
342
+ scope, or mass-scale/destructive/indiscriminate techniques.
343
+
344
+ Nyx **only changes the system prompt.** Tool access and policy gating are
345
+ completely unaffected — the `ToolRegistry`/`PolicyEngine`, not the prompt, is
346
+ the actual safety boundary (the same design used by DeepReid's role prompts).
347
+
348
+ Turn it on three ways:
349
+
350
+ ```powershell
351
+ reid --nyx # from launch
352
+ reid interactive --nyx "<prompt>"
353
+ reid exec --nyx "<prompt>"
354
+ ```
355
+
356
+ or at runtime inside the TUI:
357
+
358
+ ```
359
+ /nyx on
360
+ /nyx off
361
+ /nyx # show current state
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Subagents (`spawn_agent`)
367
+
368
+ The agent can call `spawn_agent` to run a scoped child agent inline and block
369
+ on its result — useful for parallel research, focused review, or anything
370
+ that shouldn't pollute the main conversation's context. Each child gets:
371
+
372
+ - its **own** `Agent` + `PolicyEngine` (same config/mode as the parent, but
373
+ an independent instance — a child running in a stricter mode never mutates
374
+ the parent's)
375
+ - a **filtered `ToolRegistry`** built from an explicit `tool_allowlist` (default:
376
+ `read_file`, `list_dir`, `find_files`, `grep_files` — read-only). The child
377
+ literally cannot see or call anything outside that allowlist.
378
+ - the parent's **provider/model by default**, with optional per-call overrides
379
+ - **no** `spawn_agent` of its own — one layer of nesting only, so a runaway
380
+ chain of subagents can't spawn subagents of their own
381
+
382
+ Lifecycle is reported to a `SubagentManager` that the TUI's subagent panel
383
+ subscribes to (see "The interactive TUI" above) — running/done/error, elapsed
384
+ time, last action.
385
+
386
+ ---
387
+
388
+ ## DeepReid
389
+
390
+ A real Researcher→Planner→Critic subagent pipeline for planning and
391
+ reviewing a task before any code gets written:
392
+
393
+ - **Researcher** — read-only file tools + `web_search`, investigates the
394
+ codebase/web and produces a cited Findings list. Never writes files or
395
+ runs commands.
396
+ - **Planner** — no tools, reasons only over the Findings, produces numbered
397
+ implementation steps + risks + open questions.
398
+ - **Critic** — no tools, checks the Plan against the Findings for
399
+ unsupported claims, missing cases, and contradictions; ends with a
400
+ `Verdict: ready to build | needs revision | blocked on: ...` line.
401
+ - If the Critic asks for a revision, the Planner gets one more pass (capped
402
+ at 2 rounds total) before the pipeline returns.
403
+
404
+ Each role is a fresh, independent `Agent` + `RuntimeState` + `Session` +
405
+ `PolicyEngine` — not turns on one shared conversation — so the "Planner/Critic
406
+ have no tools" constraint is real (they can't see any prior tool output). All
407
+ three run in `AUTONOMOUS` mode internally regardless of the caller's
408
+ configured mode; the restricted tool registries are the actual safety
409
+ boundary, so auto-approving inside them is safe.
410
+
411
+ Output is a Markdown plan+critique, saved to
412
+ `~/.reidx/deepreid/<run-id>.md`. Two entry points:
413
+
414
+ ```powershell
415
+ reid deepreid "<task>" # headless, like exec
416
+ ```
417
+
418
+ or type `deepread`/`deep reid` at the very start of the TUI's input box (the
419
+ border pulses green while the pipeline runs, with real-time progress shown
420
+ per stage).
421
+
422
+ DeepReid never writes files or runs commands itself — building the plan is
423
+ still the regular single-agent loop, or a human, for now (see "What is
424
+ stubbed" below).
425
+
426
+ ---
427
+
428
+ ## Configuration
429
+
430
+ Config is merged in this precedence order (low → high):
431
+
432
+ 1. **Built-in defaults** — a stub provider, balanced mode
433
+ 2. **Global config** — `~/.reidx/config.json`
434
+ 3. **Project config** — `./.reidx/config.json`
435
+ 4. **`settings.json`'s `reidx` block** (see below)
436
+ 5. **Environment variables** (highest)
437
+
438
+ ### `settings.json` (Claude-Code-shaped project settings)
439
+
440
+ ReidX also reads a Claude-Code-style `settings.json`: an `env` block
441
+ (applied to `os.environ` before anything reads credentials — this is how a
442
+ project can bake in Anthropic-compatible proxy credentials even when the
443
+ shell's own `ANTHROPIC_*` vars point somewhere else) and an optional
444
+ `reidx` block (baked-in `default_provider`, `policy`, etc.). Unknown keys
445
+ (`theme`, `effortLevel`, ...) are ignored harmlessly, so an existing Claude
446
+ Code settings file works as-is.
447
+
448
+ Path resolution (first hit wins):
449
+
450
+ 1. `$REIDCHAT_SETTINGS` (explicit override)
451
+ 2. A project-local `settings.json`, found by walking upward from the current
452
+ directory the way `git` finds `.git` — so launching `reid` from any
453
+ subdirectory of a project still finds that project's file
454
+ 3. `~/.reidx/settings.json` (global default)
455
+ 4. `E:/leech/Reidchat.json` (legacy shared file)
456
+
457
+ ### Environment variables
458
+
459
+ | Variable | Effect |
460
+ |---|---|
461
+ | `REIDX_PROVIDER` | Default provider name (e.g. `stub`) |
462
+ | `REIDX_WORKSPACE` | Workspace root path |
463
+ | `REIDX_STORAGE` | Storage root path (defaults to `~/.reidx`) |
464
+ | `REIDX_PERMISSION_MODE` | Permission mode: `strict` `balanced` `autonomous` `custom` |
465
+ | `REIDX_LOG_LEVEL` | Log level: `INFO` `DEBUG` `WARNING` `ERROR` |
466
+ | `REIDCHAT_SETTINGS` | Explicit path override for the `settings.json` lookup above |
467
+ | `ANTHROPIC_API_KEY` / `ANTHROPIC_BASE_URL` / `ANTHROPIC_MODEL` | Auto-registers an `anthropic` provider at startup (never made default; `/use anthropic`) |
468
+
469
+ ### Config file example
470
+
471
+ `~/.reidx/config.json`:
472
+
473
+ ```json
474
+ {
475
+ "default_provider": "stub",
476
+ "policy": {
477
+ "default_mode": "balanced",
478
+ "allowed_commands": ["git", "ls", "pwd"],
479
+ "shell_timeout_seconds": 30
480
+ }
481
+ }
482
+ ```
483
+
484
+ View the effective merged config:
485
+
486
+ ```powershell
487
+ reid config-show
488
+ ```
489
+
490
+ ---
491
+
492
+ ## Permission modes
493
+
494
+ The policy engine gates every tool call. Pick a mode that matches your trust level.
495
+
496
+ | Mode | Behavior |
497
+ |---|---|
498
+ | `strict` | Approve nearly everything. File reads allowed; writes prompt; shell denied. |
499
+ | `balanced` | (Default) Low-risk allowed; medium and high risk prompt for approval. |
500
+ | `autonomous` | Low and medium allowed without prompts; high risk still prompts. |
501
+ | `custom` | Only explicit allowlists permit; everything else prompts. |
502
+
503
+ Path confinement is enforced in all modes — file tools cannot read or write outside
504
+ the workspace root (plus any configured `additional_writable_roots`). Shell commands
505
+ in the default denylist (`rm`, `rmdir`, `del`, `format`, `shutdown`, `reboot`, `mkfs`)
506
+ are always blocked.
507
+
508
+ This same policy engine is what actually gates `spawn_agent` children and Nyx
509
+ mode — neither persona nor tool inheritance bypasses it.
510
+
511
+ Switch modes at runtime:
512
+
513
+ ```
514
+ /mode strict
515
+ /mode autonomous
516
+ ```
517
+
518
+ ---
519
+
520
+ ## Tools
521
+
522
+ The agent loop calls tools through the registry. Each tool is policy-gated.
523
+
524
+ | Tool | Risk | Purpose |
525
+ |---|---|---|
526
+ | `read_file` | low | Read a file's text content |
527
+ | `write_file` | medium | Create or overwrite a file |
528
+ | `patch_file` | medium | Replace one exact substring occurrence (unique match required) |
529
+ | `list_dir` | low | List entries in a directory |
530
+ | `find_files` | low | Find files matching a glob pattern |
531
+ | `grep_files` | low | Search file contents with a regex |
532
+ | `run_command` | high | Run a shell command with policy approval and timeout |
533
+ | `web_search` | high | Search the web (DuckDuckGo, free, no API key) — see below |
534
+ | `spawn_agent` | medium | Run a scoped child agent (own policy engine + tool allowlist) and block for its result — see "Subagents" above |
535
+
536
+ All file tools confine access to the workspace root. Traversal outside is denied.
537
+
538
+ ### `web_search`
539
+
540
+ Free, no API key, stdlib-only (`urllib` + `re`). Two DuckDuckGo sources, tried
541
+ in order:
542
+
543
+ 1. The official Instant Answer JSON API — fast (~0.3s), but only populated
544
+ for factual/entity queries ("what is X").
545
+ 2. The HTML-only search endpoint — slower and more exposed to DuckDuckGo's
546
+ anti-bot rate limiting, but covers general search queries the fast path
547
+ doesn't.
548
+
549
+ Results are cached in-memory per session (5 minute TTL) so repeated queries
550
+ don't re-hit the network. Sponsored/ad results are filtered out rather than
551
+ surfaced as raw tracking links. Gated as `ActionKind.NETWORK` (HIGH risk by
552
+ default) through the same policy engine as every other tool — expect an
553
+ approval prompt in `balanced`/`strict` mode.
554
+
555
+ ---
556
+
557
+ ## Sessions and persistence
558
+
559
+ Each session gets a structured directory under `~/.reidx/sessions/<id>/`:
560
+
561
+ ```
562
+ ~/.reidx/sessions/<session-id>/
563
+ meta.json # Session record (id, workspace, model, mode, status, timestamps)
564
+ transcript.jsonl # One Message per line (restorable into state on resume)
565
+ tasks.json # Task state for the session
566
+ goals.json # Goal hierarchy, evidence, active goal, revisions
567
+ events.jsonl # Runtime action log (turn summaries, lifecycle events)
568
+ ```
569
+
570
+ Workflows and connected providers live one level up, outside any single session:
571
+
572
+ ```
573
+ ~/.reidx/workflows.json # {"workflows": [{name, description, steps, created_at}, ...]}
574
+ ~/.reidx/providers.json # {"providers": [{name, kind, base_url, api_key, default_model}, ...]} (chmod 600)
575
+ ```
576
+
577
+ **Resume is real:** `reid resume <id>` reloads the transcript into the agent's
578
+ message history so the conversation continues with full context (capped at the 100
579
+ most recent messages).
580
+
581
+ List sessions:
582
+
583
+ ```powershell
584
+ reid sessions
585
+ ```
586
+
587
+ ---
588
+
589
+ ## Headless / exec mode
590
+
591
+ Run a single prompt without entering the TUI:
592
+
593
+ ```powershell
594
+ reid exec "list the current dir"
595
+ reid exec "read README.md"
596
+ reid exec --file prompt.txt
597
+ reid exec --nyx "recon plan for <authorized target>"
598
+ ```
599
+
600
+ Output goes to stdout; tool-call count goes to stderr. Exit code is `0` on success,
601
+ `1` if no text was produced. The approver auto-allows in exec mode — set
602
+ `REIDX_PERMISSION_MODE=autonomous` for unattended runs, or `strict` to deny all
603
+ risky actions silently.
604
+
605
+ ---
606
+
607
+ ## Development
608
+
609
+ ### Run the test suite
610
+
611
+ ```powershell
612
+ pytest
613
+ ```
614
+
615
+ 43 focused tests cover policy, tools, session/task/goal persistence, reasoning,
616
+ the agent loop, DeepReid, and providers/subagents.
617
+
618
+ ### Lint
619
+
620
+ ```powershell
621
+ ruff check src tests
622
+ ruff check --fix src tests # auto-fix
623
+ ```
624
+
625
+ ### Project structure
626
+
627
+ ```
628
+ ReidX/
629
+ pyproject.toml
630
+ src/reidx/
631
+ app/ # Typer CLI commands, dependency wiring
632
+ config/ # Pydantic config models + loader (global/project/settings.json/env merge)
633
+ diagnostics/ # logger + JSONL event log
634
+ session/ # Session model + structured per-session store
635
+ tasks/ # Task model + store (state machine)
636
+ goals/ # Goal model + per-session goal hierarchy/evidence store
637
+ policy/ # PermissionMode, decisions, risk, PolicyEngine
638
+ provider/ # BaseProvider + StubProvider + Anthropic/OpenAI/OpenAI-compatible/Ollama
639
+ # + ProviderRegistry + ProviderStore (persisted /connect records)
640
+ tools/ # ToolDefinition/Result, registry, file/shell/web-search/spawn_agent tools
641
+ workflows/ # Workflow model + global WorkflowStore (~/.reidx/workflows.json)
642
+ nyx/ # Nyx redteam/offensive-security persona (system-prompt swap only)
643
+ deepreid/ # Researcher->Planner->Critic planning-and-review pipeline
644
+ runtime/ # RuntimeState, agent loop, orchestrator (composition root), subagent manager
645
+ integrations/# MCP foundation (config-driven, stubbed lifecycle)
646
+ automation/ # exec mode (headless)
647
+ ui/ # theme, render (Rich), app (full-screen prompt_toolkit TUI),
648
+ # commands (slash-command routing + completion source), repl (entry point)
649
+ tests/ # policy, tools, session, reasoning, agent loop, deepreid, providers/subagents
650
+ docs/ # architecture audit, phase plans
651
+ ```
652
+
653
+ ### Architecture intent
654
+
655
+ See the parent repo's design docs:
656
+
657
+ - `reidx-build-plan.md` — full product definition and phase plan
658
+ - `agent-first-cli-spec.md` — generic agent-first CLI specification
659
+ - `docs/reidx-architecture-audit.md` — file-aware critique of this scaffold
660
+ - `docs/reidx-phase-5-plan.md` — correctness fixes + interaction upgrade
661
+ - `../deepreid-spec.md` — spec for DeepReid, the planning/review multi-agent
662
+ subsystem, now implemented (see above)
663
+
664
+ ---
665
+
666
+ ## What works now
667
+
668
+ - Full-screen TUI (prompt_toolkit): locked-to-bottom footer, mouse-wheel
669
+ scrollable history, collapsible reasoning/tool-call output (`Ctrl+O`), live
670
+ subagent panel, `Esc`-to-stop-response, live `/` completion menu
671
+ - Real agent loop with tool calls (StubProvider by default, no API keys
672
+ needed; real Anthropic/OpenAI/OpenAI-compatible/Ollama providers available
673
+ via env vars or `/connect`)
674
+ - Session create / list / resume with message history restoration
675
+ - Task tracking with status state machine (pending → active → completed/failed/skipped)
676
+ - Goals: `/goal` manages per-session outcome/evidence/subgoal/milestone state
677
+ in `goals.json`; active goals are linked into new task metadata
678
+ - Policy engine with 4 modes, path confinement, command allowlist/denylist —
679
+ the single safety boundary for every tool, including subagents and Nyx mode
680
+ - 9 tools (file read/write/patch/list/find/grep + shell + free web search +
681
+ spawn_agent) all policy-gated
682
+ - Workflows: save/list/show/run/delete reusable multi-step command sequences
683
+ - Providers: real HTTP clients (Anthropic/OpenAI/OpenAI-compatible/Ollama),
684
+ `/connect`/`/disconnect`/`/use`/`/providers`, persisted to
685
+ `~/.reidx/providers.json`
686
+ - Subagents: `spawn_agent` tool runs a scoped child agent (own policy engine +
687
+ tool allowlist, one layer of nesting), live TUI panel showing progress
688
+ - **DeepReid** (`src/reidx/deepreid/`): a real Researcher→Planner→Critic
689
+ subagent pipeline — each role is an independent `Agent`/`PolicyEngine`
690
+ (Planner/Critic get zero tools; Researcher gets read-only file tools +
691
+ `web_search` only), sequential, with a Critic-driven revision loop capped
692
+ at 2 rounds. Never writes files or runs commands — output is a Markdown
693
+ plan+critique, saved to `~/.reidx/deepreid/<run-id>.md`. Two entry
694
+ points: `reid deepreid "<task>"` (headless CLI, like `exec`) and typing
695
+ `deepread`/`deep reid` at the start of the TUI's input box (border pulses
696
+ green while active, real-time progress shown per stage).
697
+ - **Nyx**: redteam/offensive-security persona, toggled via `--nyx` or
698
+ `/nyx on|off` — swaps the system prompt only; tool access/policy gating are
699
+ unchanged
700
+ - Claude-Code-shaped `settings.json` support (env block + baked-in `reidx`
701
+ config block), project-local with upward directory search
702
+ - Prompt injection at launch: literal argument, `--file`, or piped stdin
703
+ - Headless exec mode
704
+ - Structured persistence (meta / transcript / tasks / goals / events per session;
705
+ global workflows, providers, and DeepReid runs)
706
+ - Test suite passing, ruff clean
707
+
708
+ ## What is stubbed (extension-ready)
709
+
710
+ - **MCP** — config schema + lifecycle slots; stdio/JSON-RPC is TODO
711
+ - **Patch tool** — single exact-match replace; structured edits + diff preview TODO
712
+ - **Automation** — one-shot exec; scheduling/background TODO
713
+ - **DeepReid Builder role** — a subagent that actually implements an
714
+ approved plan is explicitly out of scope for v1 (per `../deepreid-spec.md`);
715
+ building is still the regular single-agent loop, or a human, for now.
716
+ - **Escape-to-stop** only interrupts the normal turn loop (`Agent.run_turn`);
717
+ the DeepReid pipeline and its subagent calls don't currently check
718
+ cancellation.
719
+
720
+ ---
721
+
722
+ ## License
723
+
724
+ MIT