outrage 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- outrage-0.1.0/.claude/RESUME.md +23 -0
- outrage-0.1.0/.claude/agents/rage-annotate.md +1 -0
- outrage-0.1.0/.claude/agents/rage-backfill.md +1 -0
- outrage-0.1.0/.claude/agents/rage-search.md +1 -0
- outrage-0.1.0/.claude/skills/rage/SKILL.md +155 -0
- outrage-0.1.0/.gitignore +29 -0
- outrage-0.1.0/.mcp.json +18 -0
- outrage-0.1.0/CLAUDE.md +25 -0
- outrage-0.1.0/LICENSE +9 -0
- outrage-0.1.0/PKG-INFO +130 -0
- outrage-0.1.0/README.md +107 -0
- outrage-0.1.0/design.md +731 -0
- outrage-0.1.0/docs/Makefile +26 -0
- outrage-0.1.0/docs/api/bulk.rst +4 -0
- outrage-0.1.0/docs/api/cli.rst +4 -0
- outrage-0.1.0/docs/api/config.rst +4 -0
- outrage-0.1.0/docs/api/errors.rst +5 -0
- outrage-0.1.0/docs/api/eventlog.rst +4 -0
- outrage-0.1.0/docs/api/index.rst +70 -0
- outrage-0.1.0/docs/api/install.rst +4 -0
- outrage-0.1.0/docs/api/keys.rst +4 -0
- outrage-0.1.0/docs/api/logread.rst +4 -0
- outrage-0.1.0/docs/api/maintenance.rst +4 -0
- outrage-0.1.0/docs/api/messages.rst +4 -0
- outrage-0.1.0/docs/api/mounts.rst +4 -0
- outrage-0.1.0/docs/api/server.rst +4 -0
- outrage-0.1.0/docs/api/store.rst +4 -0
- outrage-0.1.0/docs/api/store_parquet.rst +4 -0
- outrage-0.1.0/docs/api/store_sqlite.rst +4 -0
- outrage-0.1.0/docs/conf.py +65 -0
- outrage-0.1.0/docs/index.rst +36 -0
- outrage-0.1.0/environment.yml +5 -0
- outrage-0.1.0/implementation.md +474 -0
- outrage-0.1.0/pyproject.toml +55 -0
- outrage-0.1.0/requirements.md +174 -0
- outrage-0.1.0/src/outrage/__init__.py +3 -0
- outrage-0.1.0/src/outrage/__main__.py +6 -0
- outrage-0.1.0/src/outrage/agents/rage-annotate.md +108 -0
- outrage-0.1.0/src/outrage/agents/rage-backfill.md +78 -0
- outrage-0.1.0/src/outrage/agents/rage-search.md +137 -0
- outrage-0.1.0/src/outrage/bulk.py +593 -0
- outrage-0.1.0/src/outrage/cli.py +1358 -0
- outrage-0.1.0/src/outrage/config.py +296 -0
- outrage-0.1.0/src/outrage/errors.py +63 -0
- outrage-0.1.0/src/outrage/eventlog.py +291 -0
- outrage-0.1.0/src/outrage/hooks/README.md +35 -0
- outrage-0.1.0/src/outrage/hooks/settings.json +14 -0
- outrage-0.1.0/src/outrage/install.py +423 -0
- outrage-0.1.0/src/outrage/keys.py +672 -0
- outrage-0.1.0/src/outrage/logread.py +736 -0
- outrage-0.1.0/src/outrage/maintenance.py +335 -0
- outrage-0.1.0/src/outrage/messages.py +549 -0
- outrage-0.1.0/src/outrage/mounts.py +710 -0
- outrage-0.1.0/src/outrage/server.py +1419 -0
- outrage-0.1.0/src/outrage/store.py +1374 -0
- outrage-0.1.0/src/outrage/store_parquet.py +1303 -0
- outrage-0.1.0/src/outrage/store_sqlite.py +1313 -0
- outrage-0.1.0/tests/conftest.py +68 -0
- outrage-0.1.0/tests/test_agents.py +110 -0
- outrage-0.1.0/tests/test_bulk.py +452 -0
- outrage-0.1.0/tests/test_cli.py +1353 -0
- outrage-0.1.0/tests/test_config.py +407 -0
- outrage-0.1.0/tests/test_eventlog.py +246 -0
- outrage-0.1.0/tests/test_harness_delivery.py +182 -0
- outrage-0.1.0/tests/test_install.py +437 -0
- outrage-0.1.0/tests/test_keys.py +523 -0
- outrage-0.1.0/tests/test_logread.py +478 -0
- outrage-0.1.0/tests/test_messages.py +196 -0
- outrage-0.1.0/tests/test_mounts.py +1258 -0
- outrage-0.1.0/tests/test_public_api.py +151 -0
- outrage-0.1.0/tests/test_server.py +743 -0
- outrage-0.1.0/tests/test_skill.py +49 -0
- outrage-0.1.0/tests/test_store.py +1890 -0
- outrage-0.1.0/tests/test_store_parquet.py +901 -0
- outrage-0.1.0/tests/test_store_sqlite.py +357 -0
- outrage-0.1.0/tools/harness_delivery.py +534 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Claude Code — resume checkpoint
|
|
2
|
+
|
|
3
|
+
Session: 440063bd-742b-41f8-8b80-0b5fe1852641
|
|
4
|
+
Written: 2026-08-21T11:20:15.294Z
|
|
5
|
+
Trigger: near-limit
|
|
6
|
+
Ref with your in-progress files: refs/claude/checkpoint-440063bd
|
|
7
|
+
|
|
8
|
+
## To resume
|
|
9
|
+
|
|
10
|
+
claude --resume 440063bd-742b-41f8-8b80-0b5fe1852641
|
|
11
|
+
|
|
12
|
+
(or open Claude Code in this directory and run /resume)
|
|
13
|
+
|
|
14
|
+
## Plan (from TodoWrite state)
|
|
15
|
+
|
|
16
|
+
No task list was active; see transcript via the resume command above.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
Don't want these changes? Resume this session (above), then run
|
|
21
|
+
`/rewind` to roll back the turn's tool edits (bash-made changes
|
|
22
|
+
excluded). refs/claude/checkpoint-440063bd holds a full snapshot until this session's
|
|
23
|
+
next checkpoint, or for up to ~2 weeks.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
../../src/outrage/agents/rage-annotate.md
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
../../src/outrage/agents/rage-backfill.md
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
../../src/outrage/agents/rage-search.md
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rage
|
|
3
|
+
description: Keep and recover working knowledge in this project's rage document store - notes, decisions, findings and task state that outlive one session. Use when starting or resuming work and the question is what earlier sessions established ("where were we", "what do we already know about X", "continue", "pick up where we left off"); when something worth keeping has just been settled (a decision and its reasoning, a finding that took effort to get, where the work got to); when asked to remember, store or save context; and before a session ends or its context is compacted.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# The rage store
|
|
7
|
+
|
|
8
|
+
A document store for this project, reached through the `rage` MCP tools. The
|
|
9
|
+
tools carry the key grammar and the argument rules; this skill covers when to
|
|
10
|
+
use them and what to name things.
|
|
11
|
+
|
|
12
|
+
## Start at `readme`
|
|
13
|
+
|
|
14
|
+
Every store's entry point is the document at `readme`: what this particular
|
|
15
|
+
store holds, and what to read before anything else. The server carries it at
|
|
16
|
+
the top of its instructions, so it arrives without being asked for and there is
|
|
17
|
+
normally nothing to do here. If it did not arrive, read it.
|
|
18
|
+
|
|
19
|
+
Three things follow from that. A readme long enough to be worth summarising is
|
|
20
|
+
too long - it routes, and the documents it points at explain. It has a hard cap
|
|
21
|
+
of a few hundred characters, because a client cuts the instructions at a length
|
|
22
|
+
it does not announce and the readme is what has to survive that cut; over the
|
|
23
|
+
cap the server reports its length instead of carrying it, which is the signal
|
|
24
|
+
to go and read it. And a store with no readme is asking for one: a session that
|
|
25
|
+
works out how the store is laid out, or what the next session should read
|
|
26
|
+
first, should write that there.
|
|
27
|
+
|
|
28
|
+
It is read once, when the server starts, so a readme stored now reaches the
|
|
29
|
+
next session rather than this one.
|
|
30
|
+
|
|
31
|
+
## Survey before reading
|
|
32
|
+
|
|
33
|
+
One call shows what the store holds:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
get_documents(meta_name=["title"])
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That returns a title per document, not the documents, so it is cheap enough to
|
|
40
|
+
run at the start of any piece of work. Then read only what looks relevant, with
|
|
41
|
+
`retrieve_document`.
|
|
42
|
+
|
|
43
|
+
**Read `total`, not just what came back.** The result is a page: `returned`
|
|
44
|
+
titles out of `total` documents, with `next_cursor` set when there are more.
|
|
45
|
+
Twenty of twenty-two is a listing and you have seen the store; twenty of four
|
|
46
|
+
thousand is a sample, and treating it as the store is how a session concludes
|
|
47
|
+
confidently from a fraction of it. To continue, pass `next_cursor` back as
|
|
48
|
+
`after`. To look at one part instead of everything, pass `key`.
|
|
49
|
+
|
|
50
|
+
Check `without_meta` too. It reports how many documents carry no title, with a
|
|
51
|
+
few of their keys - the ones the survey cannot show at all, since it can only
|
|
52
|
+
report documents that have one. A survey that omits them silently is a survey
|
|
53
|
+
you cannot trust. It is always present, and it covers exactly the stretch of
|
|
54
|
+
the store this page covers, so paging the survey walks the gaps alongside the
|
|
55
|
+
titles instead of repeating a subtree-wide total on every page.
|
|
56
|
+
|
|
57
|
+
It is a count, not a listing, and carries no cursor: `keys_missing_meta` is
|
|
58
|
+
what enumerates them, and `rage-backfill` fills them in.
|
|
59
|
+
|
|
60
|
+
## Key conventions
|
|
61
|
+
|
|
62
|
+
Three top level namespaces. Nothing enforces them; they exist so that a later
|
|
63
|
+
session can guess where to look.
|
|
64
|
+
|
|
65
|
+
`context/<n>/…` - one numbered thread of work. Do not invent the number: store
|
|
66
|
+
at `context/?/task` first and the result reports the key it allocated, then put
|
|
67
|
+
everything else in that thread alongside it.
|
|
68
|
+
|
|
69
|
+
* `context/<n>/task` - what is being attempted, in a few lines.
|
|
70
|
+
* `context/<n>/state` - where it got to, what is unfinished, what to do next.
|
|
71
|
+
* `context/<n>/design`, `…/findings`, `…/decisions` - whatever the work
|
|
72
|
+
produced that is worth keeping.
|
|
73
|
+
|
|
74
|
+
`project/reference/<topic>` - durable facts about the project itself, belonging
|
|
75
|
+
to no single thread: the environment, conventions, current status. Updated in
|
|
76
|
+
place as they change.
|
|
77
|
+
|
|
78
|
+
`notes/<path>` - notes about one file, keyed to mirror its path, as in
|
|
79
|
+
`notes/src/outrage/store.py`.
|
|
80
|
+
|
|
81
|
+
Pass `title` on every document. It is what the survey above can see, and a
|
|
82
|
+
document without one is findable only by someone who already knows its key.
|
|
83
|
+
|
|
84
|
+
Store a `!summary` as well for any document whose subject its title cannot
|
|
85
|
+
carry. `rage-search` screens on title *then* summary, so a document with a
|
|
86
|
+
title and no summary is judged on the title alone - and "Notes from the Tuesday
|
|
87
|
+
run" is an honest title that tells a reader nothing. Aim for about a fifth of
|
|
88
|
+
the document: a summary that approaches the length of its document costs as much
|
|
89
|
+
to screen as the document costs to read. `rage-backfill` fills these in across a subtree,
|
|
90
|
+
which is the right thing to run after adding several documents at once.
|
|
91
|
+
|
|
92
|
+
## What is worth storing
|
|
93
|
+
|
|
94
|
+
Store what cost something to learn and that nothing else in the project
|
|
95
|
+
records:
|
|
96
|
+
|
|
97
|
+
* a decision, and why the alternative was rejected
|
|
98
|
+
* a finding from actually running the thing - an error, a behaviour, a
|
|
99
|
+
constraint in a dependency
|
|
100
|
+
* where the work got to, and what the next step is
|
|
101
|
+
* a correction: something believed at the start of the session and found false
|
|
102
|
+
|
|
103
|
+
Do not store what the repository already holds - what the code does, what the
|
|
104
|
+
diff changed, what the commit messages say. A note restating the code is a note
|
|
105
|
+
that will go stale and then mislead, and it costs a later session the read.
|
|
106
|
+
|
|
107
|
+
The test is whether someone could act on the document without the session that
|
|
108
|
+
wrote it.
|
|
109
|
+
|
|
110
|
+
## Store as the work goes, not at the end
|
|
111
|
+
|
|
112
|
+
Store each thing once it is settled. A session that plans to write everything up
|
|
113
|
+
at the end stores nothing if it is cut short, and a full context window is
|
|
114
|
+
exactly the ending that arrives without warning.
|
|
115
|
+
|
|
116
|
+
Rewrite the same key rather than accumulating new ones: `context/1/state` should
|
|
117
|
+
be the current state, not the first of several. Storing overwrites, which is
|
|
118
|
+
what makes this cheap.
|
|
119
|
+
|
|
120
|
+
Keep `project/reference/…` current when the facts under it change. A stale
|
|
121
|
+
reference is worse than an absent one, because it is believed.
|
|
122
|
+
|
|
123
|
+
## One document, one question
|
|
124
|
+
|
|
125
|
+
Rewriting a key keeps it current; it is not licence to let it grow. When there
|
|
126
|
+
is more to keep, prefer **adding a document beneath it** to extending the one
|
|
127
|
+
that is there. Sub-documents are the intended shape, and `?` allocates a key at
|
|
128
|
+
any depth - `context/1/findings/?` writes the next document under `findings` -
|
|
129
|
+
so adding one costs no naming decision and no thought about where it goes.
|
|
130
|
+
|
|
131
|
+
A document should be readable in one call. `retrieve_document` returns 8000
|
|
132
|
+
characters by default, so a longer document is read in slices, and a session
|
|
133
|
+
that judges it from the first slice judges it wrongly and silently.
|
|
134
|
+
|
|
135
|
+
Size is the symptom; scope is the cause. `project/reference/planned` reached
|
|
136
|
+
11389 characters because it answered five questions at once - what CLI pieces
|
|
137
|
+
remain, what is open on the agents, what the log reader should do, how the
|
|
138
|
+
checkpoint prompt gets delivered, which files are stale. No title and no
|
|
139
|
+
summary can route a reader to the right part of a document like that, so it is
|
|
140
|
+
read whole or not at all.
|
|
141
|
+
|
|
142
|
+
Split along the questions, not by length. A key can hold content *and* have
|
|
143
|
+
keys beneath it, so the general document stays where it is and the detail goes
|
|
144
|
+
below: `project/reference/planned` is now a short index over `planned/cli`,
|
|
145
|
+
`planned/agents`, `planned/log-reader` and the rest. Anything already pointing
|
|
146
|
+
at the old key still lands somewhere useful, which is what makes a split safe
|
|
147
|
+
to do late - but adding as you go is cheaper than splitting afterwards.
|
|
148
|
+
|
|
149
|
+
## Before the end
|
|
150
|
+
|
|
151
|
+
Whether the session is ending, being handed over, or about to be compacted:
|
|
152
|
+
|
|
153
|
+
* make sure `context/<n>/state` actually describes where things stand
|
|
154
|
+
* store anything settled that is still only in the conversation
|
|
155
|
+
* check the survey - anything under `without_meta` needs a title
|
outrage-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.pytest_cache/
|
|
4
|
+
.ruff_cache/
|
|
5
|
+
*.egg-info/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
.env
|
|
10
|
+
*.sqlite
|
|
11
|
+
*.sqlite3
|
|
12
|
+
*.db
|
|
13
|
+
.outrage/
|
|
14
|
+
.rage/
|
|
15
|
+
.DS_Store
|
|
16
|
+
.claude/settings.local.json
|
|
17
|
+
.claude/harness-canary/
|
|
18
|
+
|
|
19
|
+
# The SessionStart canary probes the client, not this project: it is
|
|
20
|
+
# registered in the untracked settings.local.json, its log above is ignored,
|
|
21
|
+
# and it ships nowhere. It stays on the machine that runs it.
|
|
22
|
+
.claude/hooks/sessionstart_canary.py
|
|
23
|
+
.claude/hooks/sessionstart-canary.sh
|
|
24
|
+
.claude/settings.json
|
|
25
|
+
.outrage-*/
|
|
26
|
+
.rage-*/
|
|
27
|
+
|
|
28
|
+
# Sphinx build output
|
|
29
|
+
docs/_build/
|
outrage-0.1.0/.mcp.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"rage": {
|
|
4
|
+
"command": "/Users/john/miniforge3/envs/rage/bin/outrage-server",
|
|
5
|
+
"args": [
|
|
6
|
+
"--dir",
|
|
7
|
+
"/Users/john/Library/CloudStorage/OneDrive-Personal/Projects/Rage/.outrage",
|
|
8
|
+
"--mount",
|
|
9
|
+
"mount_test=mount-test.sqlite",
|
|
10
|
+
"--mount-ro",
|
|
11
|
+
"ref=ref.sqlite",
|
|
12
|
+
"--mount-ro",
|
|
13
|
+
"pyref=python.parquet",
|
|
14
|
+
"--log"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
outrage-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Outrage
|
|
2
|
+
|
|
3
|
+
This project keeps its working knowledge - decisions, findings, and where the
|
|
4
|
+
work got to - in its own rage document store, reached through the `rage` MCP
|
|
5
|
+
tools. That store is the record. **This file is only a pointer to it**, so that
|
|
6
|
+
nothing here can go stale against what the store says.
|
|
7
|
+
|
|
8
|
+
## Start here
|
|
9
|
+
|
|
10
|
+
Read the document at key `project`. It is an index of what to read and *when it
|
|
11
|
+
applies*, and it routes to everything else. A survey by title
|
|
12
|
+
(`get_documents(meta_name=["title"])`) tells you what documents are about; the
|
|
13
|
+
`project` document tells you which one you need before you know to look.
|
|
14
|
+
|
|
15
|
+
## Before snapshotting the store
|
|
16
|
+
|
|
17
|
+
Read `project/reference/snapshots` first. Copying `.outrage/store.sqlite` with `cp`
|
|
18
|
+
succeeds and produces a **silently stale** store, potentially a whole schema
|
|
19
|
+
version behind. Use `outrage backup`.
|
|
20
|
+
|
|
21
|
+
## Conventions
|
|
22
|
+
|
|
23
|
+
The `rage` skill (`.claude/skills/rage/SKILL.md`) holds the key conventions and
|
|
24
|
+
what is worth storing. The tools themselves carry the key grammar and the
|
|
25
|
+
argument rules.
|
outrage-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 John M Reynolds
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
outrage-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: outrage
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A key-addressed retrieval system for coding agents
|
|
5
|
+
Project-URL: Homepage, https://github.com/ZandevOxford/outrage
|
|
6
|
+
Project-URL: Issues, https://github.com/ZandevOxford/outrage/issues
|
|
7
|
+
Author-email: John M Reynolds <zandev@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.14
|
|
13
|
+
Requires-Dist: mcp>=1.2
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
16
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
17
|
+
Provides-Extra: docs
|
|
18
|
+
Requires-Dist: furo; extra == 'docs'
|
|
19
|
+
Requires-Dist: sphinx>=8; extra == 'docs'
|
|
20
|
+
Provides-Extra: parquet
|
|
21
|
+
Requires-Dist: pyarrow>=18; extra == 'parquet'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# Outrage
|
|
25
|
+
|
|
26
|
+
A simple retrieval system for coding agents: an MCP server, a data store, and
|
|
27
|
+
skills that let an agent keep notes, designs and task context in a store local
|
|
28
|
+
to the project it is working on.
|
|
29
|
+
|
|
30
|
+
Retrieval is by key rather than by similarity. Keys are hierarchical, slash
|
|
31
|
+
delimited strings such as `context/<guid>/design`, and any key may carry
|
|
32
|
+
metadata such as `context/<guid>/design/!title`. Since an agent knows the keys it
|
|
33
|
+
wrote, lexical addressing is enough, and the system stays deterministic and free
|
|
34
|
+
of external dependencies. Semantic search is a possible later addition, layered
|
|
35
|
+
on as metadata rather than as a change to the model.
|
|
36
|
+
|
|
37
|
+
Keys are not paths, but they are shaped like them, so a key can mirror one:
|
|
38
|
+
`notes/src/myfile.py` for notes about a source file. A key being written may
|
|
39
|
+
also use `?` in place of a segment - storing at `tmp/?` writes to `tmp/1`, and
|
|
40
|
+
the store reports the key it chose.
|
|
41
|
+
|
|
42
|
+
## Purpose
|
|
43
|
+
|
|
44
|
+
To provide a hierarchical RAG (Retrieval-Augmented Generation) MCP store to use
|
|
45
|
+
with LLM based tools.
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
* Simple to get started with - built in initialisation configures everything.
|
|
50
|
+
* Hierarchical store of data and metadata.
|
|
51
|
+
* LLM search - LLM subagents add summary metadata to documents, and LLM subagents can
|
|
52
|
+
search documents and metadata.
|
|
53
|
+
* Multiple data stores including parquet based stores for large-scale reference material.
|
|
54
|
+
|
|
55
|
+
## Status
|
|
56
|
+
|
|
57
|
+
The store, the MCP server, the key handling, the skill and the command line tool
|
|
58
|
+
are implemented. The tool covers the store operations (`outrage get`, `set`,
|
|
59
|
+
`ls`, `dump`, `rm`), bulk export and import to a directory of files (`outrage
|
|
60
|
+
export`, `outrage import`), building a read-only parquet store (`outrage pack`),
|
|
61
|
+
the MCP configuration (`outrage config`), a verified backup (`outrage backup`),
|
|
62
|
+
the event log (`outrage log`), and setting a project up (`outrage init`). See
|
|
63
|
+
[implementation.md](implementation.md) for what is done and what is next.
|
|
64
|
+
|
|
65
|
+
`outrage init` is the way in: run it in a project and it registers the MCP
|
|
66
|
+
server, installs the `SessionStart` hook, and copies the skill and the agents
|
|
67
|
+
into `.claude/`. It writes only the entries outrage owns, leaves the rest of
|
|
68
|
+
those files alone, and is safe to re-run - which is how a project is repaired
|
|
69
|
+
after an upgrade or after the environment moves. `--dry-run` reports what it
|
|
70
|
+
would change without writing.
|
|
71
|
+
|
|
72
|
+
## Documentation
|
|
73
|
+
|
|
74
|
+
* **[design.md](design.md)** - the design. Components, the key namespace and its
|
|
75
|
+
grammar, tool semantics, and the SQLite schema. Decisions that are deferred or
|
|
76
|
+
still open are recorded at the end.
|
|
77
|
+
* **[implementation.md](implementation.md)** - what is implemented so far, and
|
|
78
|
+
the planned build order.
|
|
79
|
+
|
|
80
|
+
## Components
|
|
81
|
+
|
|
82
|
+
* **MCP server** - Python, stdio, for local use. Exposes the store as tools.
|
|
83
|
+
* **Data store** - a Python library, independent of MCP so that it can be tested
|
|
84
|
+
and reused on its own. One interface with two backends behind it, and which
|
|
85
|
+
one a store uses follows from its file's extension. **SQLite** is the
|
|
86
|
+
read-write default: a store accumulated a document at a time, which is what
|
|
87
|
+
session context and notes on a codebase are. **Parquet** is one columnar file,
|
|
88
|
+
written whole by `outrage pack` and read many times, for a reference base of
|
|
89
|
+
tens of thousands of documents - 11× smaller than the same corpus in SQLite,
|
|
90
|
+
and it seeks a range rather than scanning one. It refuses writes, which is the
|
|
91
|
+
storage rather than a setting.
|
|
92
|
+
* **Skill** - `src/outrage/skills/rage/SKILL.md`, initially for Claude Code,
|
|
93
|
+
covering when to store and retrieve and what key conventions to follow. It
|
|
94
|
+
ships inside the package so that an install carries it, and `outrage init`
|
|
95
|
+
copies it into a project. A `SessionStart` hook in `.claude/settings.json`,
|
|
96
|
+
installed by the same command, covers the moment a skill would not be reached
|
|
97
|
+
for on its own.
|
|
98
|
+
* **Event log** - an optional JSON lines record of the requests made and the
|
|
99
|
+
store accesses beneath them, for answering afterwards what a session actually
|
|
100
|
+
did. Off unless `outrage config --log` or `outrage-server --log` asks for it.
|
|
101
|
+
* **Backup** - `outrage backup` copies the database through SQLite and checks
|
|
102
|
+
what it wrote. In the library rather than the tool, because a store in WAL
|
|
103
|
+
mode keeps recent writes in a sidecar file and copying the `.sqlite` alone
|
|
104
|
+
yields a near-empty database that still opens cleanly.
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
conda env create -f environment.yml # or: conda create -n outrage -c conda-forge python=3.14
|
|
110
|
+
conda activate outrage
|
|
111
|
+
pip install -e ".[dev]"
|
|
112
|
+
pytest
|
|
113
|
+
ruff check . && ruff format --check .
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The stores live in a directory given to the server by `--dir` or `RAGE_DIR`,
|
|
117
|
+
defaulting to `./.outrage/` in the working directory, each as a file inside it:
|
|
118
|
+
`--root-mount FILE` names the one answering for everything (default
|
|
119
|
+
`store.sqlite`) and `--mount KEY=FILE` mounts another under a key. A store file
|
|
120
|
+
is always relative to the directory, so only `--dir` is a path. See
|
|
121
|
+
[design.md](design.md#store-location).
|
|
122
|
+
|
|
123
|
+
`outrage-server --log` records requests and store accesses as JSON lines, by
|
|
124
|
+
default in `log.jsonl` beside the store. It is off otherwise, since it records
|
|
125
|
+
document text. `--log-content none|excerpt|full` controls how much of that text
|
|
126
|
+
it keeps.
|
|
127
|
+
|
|
128
|
+
`.mcp.json` registers the server for this project. Its `command` is an absolute
|
|
129
|
+
path into the conda environment, so it is specific to the machine it was written
|
|
130
|
+
on; adjust it after creating the environment elsewhere.
|
outrage-0.1.0/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Outrage
|
|
2
|
+
|
|
3
|
+
A simple retrieval system for coding agents: an MCP server, a data store, and
|
|
4
|
+
skills that let an agent keep notes, designs and task context in a store local
|
|
5
|
+
to the project it is working on.
|
|
6
|
+
|
|
7
|
+
Retrieval is by key rather than by similarity. Keys are hierarchical, slash
|
|
8
|
+
delimited strings such as `context/<guid>/design`, and any key may carry
|
|
9
|
+
metadata such as `context/<guid>/design/!title`. Since an agent knows the keys it
|
|
10
|
+
wrote, lexical addressing is enough, and the system stays deterministic and free
|
|
11
|
+
of external dependencies. Semantic search is a possible later addition, layered
|
|
12
|
+
on as metadata rather than as a change to the model.
|
|
13
|
+
|
|
14
|
+
Keys are not paths, but they are shaped like them, so a key can mirror one:
|
|
15
|
+
`notes/src/myfile.py` for notes about a source file. A key being written may
|
|
16
|
+
also use `?` in place of a segment - storing at `tmp/?` writes to `tmp/1`, and
|
|
17
|
+
the store reports the key it chose.
|
|
18
|
+
|
|
19
|
+
## Purpose
|
|
20
|
+
|
|
21
|
+
To provide a hierarchical RAG (Retrieval-Augmented Generation) MCP store to use
|
|
22
|
+
with LLM based tools.
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
* Simple to get started with - built in initialisation configures everything.
|
|
27
|
+
* Hierarchical store of data and metadata.
|
|
28
|
+
* LLM search - LLM subagents add summary metadata to documents, and LLM subagents can
|
|
29
|
+
search documents and metadata.
|
|
30
|
+
* Multiple data stores including parquet based stores for large-scale reference material.
|
|
31
|
+
|
|
32
|
+
## Status
|
|
33
|
+
|
|
34
|
+
The store, the MCP server, the key handling, the skill and the command line tool
|
|
35
|
+
are implemented. The tool covers the store operations (`outrage get`, `set`,
|
|
36
|
+
`ls`, `dump`, `rm`), bulk export and import to a directory of files (`outrage
|
|
37
|
+
export`, `outrage import`), building a read-only parquet store (`outrage pack`),
|
|
38
|
+
the MCP configuration (`outrage config`), a verified backup (`outrage backup`),
|
|
39
|
+
the event log (`outrage log`), and setting a project up (`outrage init`). See
|
|
40
|
+
[implementation.md](implementation.md) for what is done and what is next.
|
|
41
|
+
|
|
42
|
+
`outrage init` is the way in: run it in a project and it registers the MCP
|
|
43
|
+
server, installs the `SessionStart` hook, and copies the skill and the agents
|
|
44
|
+
into `.claude/`. It writes only the entries outrage owns, leaves the rest of
|
|
45
|
+
those files alone, and is safe to re-run - which is how a project is repaired
|
|
46
|
+
after an upgrade or after the environment moves. `--dry-run` reports what it
|
|
47
|
+
would change without writing.
|
|
48
|
+
|
|
49
|
+
## Documentation
|
|
50
|
+
|
|
51
|
+
* **[design.md](design.md)** - the design. Components, the key namespace and its
|
|
52
|
+
grammar, tool semantics, and the SQLite schema. Decisions that are deferred or
|
|
53
|
+
still open are recorded at the end.
|
|
54
|
+
* **[implementation.md](implementation.md)** - what is implemented so far, and
|
|
55
|
+
the planned build order.
|
|
56
|
+
|
|
57
|
+
## Components
|
|
58
|
+
|
|
59
|
+
* **MCP server** - Python, stdio, for local use. Exposes the store as tools.
|
|
60
|
+
* **Data store** - a Python library, independent of MCP so that it can be tested
|
|
61
|
+
and reused on its own. One interface with two backends behind it, and which
|
|
62
|
+
one a store uses follows from its file's extension. **SQLite** is the
|
|
63
|
+
read-write default: a store accumulated a document at a time, which is what
|
|
64
|
+
session context and notes on a codebase are. **Parquet** is one columnar file,
|
|
65
|
+
written whole by `outrage pack` and read many times, for a reference base of
|
|
66
|
+
tens of thousands of documents - 11× smaller than the same corpus in SQLite,
|
|
67
|
+
and it seeks a range rather than scanning one. It refuses writes, which is the
|
|
68
|
+
storage rather than a setting.
|
|
69
|
+
* **Skill** - `src/outrage/skills/rage/SKILL.md`, initially for Claude Code,
|
|
70
|
+
covering when to store and retrieve and what key conventions to follow. It
|
|
71
|
+
ships inside the package so that an install carries it, and `outrage init`
|
|
72
|
+
copies it into a project. A `SessionStart` hook in `.claude/settings.json`,
|
|
73
|
+
installed by the same command, covers the moment a skill would not be reached
|
|
74
|
+
for on its own.
|
|
75
|
+
* **Event log** - an optional JSON lines record of the requests made and the
|
|
76
|
+
store accesses beneath them, for answering afterwards what a session actually
|
|
77
|
+
did. Off unless `outrage config --log` or `outrage-server --log` asks for it.
|
|
78
|
+
* **Backup** - `outrage backup` copies the database through SQLite and checks
|
|
79
|
+
what it wrote. In the library rather than the tool, because a store in WAL
|
|
80
|
+
mode keeps recent writes in a sidecar file and copying the `.sqlite` alone
|
|
81
|
+
yields a near-empty database that still opens cleanly.
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
conda env create -f environment.yml # or: conda create -n outrage -c conda-forge python=3.14
|
|
87
|
+
conda activate outrage
|
|
88
|
+
pip install -e ".[dev]"
|
|
89
|
+
pytest
|
|
90
|
+
ruff check . && ruff format --check .
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The stores live in a directory given to the server by `--dir` or `RAGE_DIR`,
|
|
94
|
+
defaulting to `./.outrage/` in the working directory, each as a file inside it:
|
|
95
|
+
`--root-mount FILE` names the one answering for everything (default
|
|
96
|
+
`store.sqlite`) and `--mount KEY=FILE` mounts another under a key. A store file
|
|
97
|
+
is always relative to the directory, so only `--dir` is a path. See
|
|
98
|
+
[design.md](design.md#store-location).
|
|
99
|
+
|
|
100
|
+
`outrage-server --log` records requests and store accesses as JSON lines, by
|
|
101
|
+
default in `log.jsonl` beside the store. It is off otherwise, since it records
|
|
102
|
+
document text. `--log-content none|excerpt|full` controls how much of that text
|
|
103
|
+
it keeps.
|
|
104
|
+
|
|
105
|
+
`.mcp.json` registers the server for this project. Its `command` is an absolute
|
|
106
|
+
path into the conda environment, so it is specific to the machine it was written
|
|
107
|
+
on; adjust it after creating the environment elsewhere.
|