tier-ctx 1.2.1__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.
Files changed (36) hide show
  1. tier_ctx-1.2.1/LICENSE +21 -0
  2. tier_ctx-1.2.1/PKG-INFO +273 -0
  3. tier_ctx-1.2.1/README.md +252 -0
  4. tier_ctx-1.2.1/pyproject.toml +31 -0
  5. tier_ctx-1.2.1/setup.cfg +4 -0
  6. tier_ctx-1.2.1/src/tier/__init__.py +53 -0
  7. tier_ctx-1.2.1/src/tier/__main__.py +5 -0
  8. tier_ctx-1.2.1/src/tier/cache.py +325 -0
  9. tier_ctx-1.2.1/src/tier/cli.py +467 -0
  10. tier_ctx-1.2.1/src/tier/context.py +369 -0
  11. tier_ctx-1.2.1/src/tier/converter.py +451 -0
  12. tier_ctx-1.2.1/src/tier/doctor.py +215 -0
  13. tier_ctx-1.2.1/src/tier/installer.py +1482 -0
  14. tier_ctx-1.2.1/src/tier/lint.py +58 -0
  15. tier_ctx-1.2.1/src/tier/mcp/__init__.py +9 -0
  16. tier_ctx-1.2.1/src/tier/mcp/__main__.py +5 -0
  17. tier_ctx-1.2.1/src/tier/mcp/sdk_server.py +183 -0
  18. tier_ctx-1.2.1/src/tier/mcp/server.py +567 -0
  19. tier_ctx-1.2.1/src/tier/memory.py +171 -0
  20. tier_ctx-1.2.1/src/tier/models.py +202 -0
  21. tier_ctx-1.2.1/src/tier/parser.py +301 -0
  22. tier_ctx-1.2.1/src/tier/pipe.py +328 -0
  23. tier_ctx-1.2.1/src/tier/plugin.py +167 -0
  24. tier_ctx-1.2.1/src/tier/repo.py +1694 -0
  25. tier_ctx-1.2.1/src/tier/retrieval.py +385 -0
  26. tier_ctx-1.2.1/src/tier/tokens.py +294 -0
  27. tier_ctx-1.2.1/src/tier/ui.py +129 -0
  28. tier_ctx-1.2.1/src/tier_ctx.egg-info/PKG-INFO +273 -0
  29. tier_ctx-1.2.1/src/tier_ctx.egg-info/SOURCES.txt +34 -0
  30. tier_ctx-1.2.1/src/tier_ctx.egg-info/dependency_links.txt +1 -0
  31. tier_ctx-1.2.1/src/tier_ctx.egg-info/entry_points.txt +4 -0
  32. tier_ctx-1.2.1/src/tier_ctx.egg-info/requires.txt +14 -0
  33. tier_ctx-1.2.1/src/tier_ctx.egg-info/top_level.txt +1 -0
  34. tier_ctx-1.2.1/tests/test_installer.py +821 -0
  35. tier_ctx-1.2.1/tests/test_tier.py +2025 -0
  36. tier_ctx-1.2.1/tests/test_v110.py +837 -0
tier_ctx-1.2.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 000jd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,273 @@
1
+ Metadata-Version: 2.4
2
+ Name: tier-ctx
3
+ Version: 1.2.1
4
+ Summary: TIER: layered context, repository graphs, code slicing, and agent memory
5
+ Author: 000jd
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Provides-Extra: ui
11
+ Requires-Dist: rich>=13.0; extra == "ui"
12
+ Provides-Extra: mcp
13
+ Requires-Dist: mcp>=2.0; extra == "mcp"
14
+ Provides-Extra: treesitter
15
+ Requires-Dist: tree-sitter-language-pack>=0.7.0; extra == "treesitter"
16
+ Provides-Extra: all
17
+ Requires-Dist: rich>=13.0; extra == "all"
18
+ Requires-Dist: mcp>=2.0; extra == "all"
19
+ Requires-Dist: tree-sitter-language-pack>=0.7.0; extra == "all"
20
+ Dynamic: license-file
21
+
22
+ <div align="center">
23
+
24
+ # TIER
25
+
26
+ **Layered context for AI coding agents: a 4-layer document and repository format, a code graph
27
+ indexer, and a zero-dependency MCP server.**
28
+
29
+ [![CI](https://github.com/000jd/tier/actions/workflows/ci.yml/badge.svg)](.github/workflows/ci.yml)
30
+ [![PyPI](https://img.shields.io/badge/pypi-tier--ctx-blue)](https://pypi.org/project/tier-ctx/)
31
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white)](pyproject.toml)
32
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
33
+
34
+ </div>
35
+
36
+ ---
37
+
38
+ `tier` keeps an agent from loading whole repositories and documents into its context. Every
39
+ document carries a small always-loadable index, one-line abstracts, structured bodies with symbol
40
+ signatures and dependency edges, and exact source-line ranges it can fetch on demand. A hybrid
41
+ retriever routes a question to the right section, an incremental repository map keeps fingerprints
42
+ and line ranges current, and a reverse-dependency graph answers what an edit affects.
43
+
44
+ The core is pure Python standard library: `dependencies = []`, no network calls, no telemetry.
45
+ It runs entirely offline on Python 3.10 and later. Optional extras add terminal styling, the
46
+ official MCP SDK adapter, and Tree-sitter grammars.
47
+
48
+ ## Installation
49
+
50
+ Zero-clone installs, in order of least commitment:
51
+
52
+ ```sh
53
+ uvx --from tier-ctx tier install # run the installer once, leave nothing installed
54
+ uv tool install tier-ctx # put `tier`, `tier-mcp`, and `tier-mcp-sdk` on PATH
55
+ pipx install tier-ctx # the same, where pipx is preferred
56
+ ```
57
+
58
+ Until the PyPI release is live, install from Git:
59
+
60
+ ```sh
61
+ uv tool install git+https://github.com/000jd/tier
62
+ uv tool install "tier-ctx[all] @ git+https://github.com/000jd/tier" # + rich UI, MCP SDK
63
+ ```
64
+
65
+ From a checkout, inside a virtual environment:
66
+
67
+ ```sh
68
+ git clone https://github.com/000jd/tier && cd tier
69
+ python3 -m venv .venv && . .venv/bin/activate
70
+ pip install -e ".[all]"
71
+ ```
72
+
73
+ > The distribution is named `tier-ctx`; the import package and console scripts are `tier`,
74
+ > `tier-mcp`, and `tier-mcp-sdk`. The bare PyPI name `tier` belongs to an unrelated package.
75
+
76
+ ## Example
77
+
78
+ An end-to-end session on a small project — install once, then one call per question:
79
+
80
+ ````console
81
+ $ tier install --clients claude-code --yes
82
+ Target: /home/me/myproject
83
+ Clients: claude-code
84
+ cache (.git/info/tier): /home/me/myproject/.git/info/tier/repo.tier (created)
85
+ Tokens: raw source 197 -> L0 130 (34.0% saved)
86
+ Instructions: /home/me/myproject/CLAUDE.md, /home/me/myproject/AGENTS.md
87
+
88
+ $ tier context . "how does the retry backoff work" --budget-tokens 800
89
+ ## Context: how does the retry backoff work
90
+
91
+ @src-http-client.py src/http/client.py
92
+ ? HTTP client with retry and backoff.; symbols: backoff_delay, request
93
+ |symbols[3]{kind,name,signature,lines}
94
+ function,backoff_delay,def backoff_delay(attempt: int) -> float,7-9
95
+ function,request,"def request(url: str, retries: int=DEFAULT_RETRIES)",12-19
96
+ function,_send,def _send(url: str),22-23
97
+ |calls[1]{caller,callee,module}
98
+ request,backoff_delay,.
99
+
100
+ @src-http-client.py#backoff_delay [L7-L9]
101
+ ```python
102
+ def backoff_delay(attempt: int) -> float:
103
+ """Exponential backoff, capped at 30 seconds."""
104
+ return min(2 ** attempt, 30.0)
105
+ ```
106
+
107
+ ## Impact: @src-http-client.py#backoff_delay
108
+ Direct dependents: @src-api-client.py
109
+ Transitive dependents: @src-api-client.py
110
+ Symbol callers: src/http/client.py#request [12-19]
111
+
112
+ $ tier impact src/http/client.py#backoff_delay
113
+ Impact target: @src-http-client.py
114
+ Direct dependents: @src-api-client.py
115
+ Transitive dependents: @src-api-client.py
116
+ Dependencies: none
117
+ Transitive dependencies: none
118
+ Symbol: src/http/client.py#backoff_delay
119
+ Symbol callers: src/http/client.py#request [12-19]
120
+ Symbol calls: none
121
+
122
+ $ tier slice src/http/client.py backoff_delay
123
+ @src-http-client.py#backoff_delay [L7-L9]
124
+ ```python
125
+ def backoff_delay(attempt: int) -> float:
126
+ """Exponential backoff, capped at 30 seconds."""
127
+ return min(2 ** attempt, 30.0)
128
+ ```
129
+ ````
130
+
131
+ ## How it works
132
+
133
+ TIER splits every document into four layers, and an agent reads only the ones it needs.
134
+
135
+ - **L0 — index.** Document metadata, global rules, and one line per section carrying that
136
+ section's token cost and rule count. Always loaded; a few hundred tokens.
137
+ - **L1 — abstracts.** A one-line `?` summary per section saying *when* to read it, folded into
138
+ the L0 index.
139
+ - **L2 — bodies.** Section contents; for codebases, a `|symbols` table with exact
140
+ `[start-end]` line ranges and `>` edges to local dependencies.
141
+ - **L3 — slices.** Exact source lines for one symbol, fetched by name.
142
+
143
+ `tier_context` collapses the whole loop into one call: resolve or build the repository index,
144
+ route the query with the hybrid retriever, match symbol names, then pack L2 bodies, L3 slices,
145
+ and a dependency summary until the token budget is spent. The granular commands remain available
146
+ when you need a specific section id or symbol.
147
+
148
+ ## Architecture highlights
149
+
150
+ **Header-once tables and indented key/value trees.** A record set is a header plus exactly N CSV
151
+ rows, and nested data is a two-space-indented tree. Both keep the schema and drop the repeated
152
+ punctuation that JSON and Markdown tables spend tokens on.
153
+
154
+ **Deterministic line-start sigils.** Every line is classified by its first character: `%` header,
155
+ `@` section, `?` abstract, `!` rule, `=` key/value, `|` counted table, `>` reference, `$` command.
156
+ Fenced code, untrusted blocks, and table rows are opaque, so no sigil inside them is reinterpreted.
157
+
158
+ **Untrusted content guards.** Text from the outside world is wrapped in `<<<source #guard ...
159
+ >>>guard`. The guards are chosen so that the payload cannot contain its own terminator, which makes
160
+ embedded instructions, fake headers, and rule sigils inert data.
161
+
162
+ **Stateful session deduplication.** A section or source slice already delivered in the conversation
163
+ is replaced by a one-line stub on the next request. `sync` evicts exactly the sections whose files
164
+ changed, and their slices.
165
+
166
+ **Symbol-level blast radius.** Repository maps record `>` edges between modules and a `|calls`
167
+ table of caller/callee pairs. `tier impact` reports file-level importers and, given
168
+ `module#symbol`, the exact functions that call it. `tier_context` filters `|calls` tables to the
169
+ 1-hop neighbourhood of the sections it returns; pass `include_calls="all"` to see every edge.
170
+
171
+ **Invisible repository cache.** The map is a derived artifact, so it lives in
172
+ `.git/info/tier/repo.tier` inside a worktree (which Git ignores) or in a user cache directory
173
+ outside it. `.git` is followed when it is a pointer file rather than a directory, so linked
174
+ worktrees and submodules resolve to their own git directory. A tracked `repo.tier` is still
175
+ honoured when one exists. Nothing is written into your working tree, so `git status` stays clean.
176
+
177
+ **Hybrid search with precomputed IDF.** BM25-style term scoring over split identifiers, a compact
178
+ synonym map, character 3-gram fallback for typos, and navigation priors. Document frequencies are
179
+ computed once per query, which keeps a search over 800 sections near 200 ms with no index to build.
180
+
181
+ ## Performance
182
+
183
+ Measured with the `o200k_base` tokenizer. These are token counts and retrieval hit rates, not LLM
184
+ answer accuracy. Methodology and reproduction steps are in
185
+ [`benchmarks/README.md`](benchmarks/README.md).
186
+
187
+ | Workload | Measure | Result |
188
+ |---|---|---|
189
+ | Repository overview | raw source → full map → L0 → L0 + one module | 72,859 → 14,375 → 828 → 1,784 tokens (−98%) |
190
+ | End-to-end 4-layer workflow | index, find, L2, L3 slices, impact + sync | 5,003 tokens (−93.1%), 3/3 exact slices |
191
+ | 36-file polyglot repository | surgical L0 + target L2 + 7 slices | 3,008 vs 8,249 tokens (−64%), 116/116 symbols |
192
+ | 197-section blind retrieval | 15 queries | 15/15 hit@1, mean top-1 fetch 134 tokens |
193
+
194
+ [`benchmarks/BENCH.txt`](benchmarks/BENCH.txt) carries the full Track A–I breakdown, including the
195
+ record-encoding and nested-config tracks, the per-query retrieval logs, and the raw output behind
196
+ every row above.
197
+
198
+ ## Supported clients
199
+
200
+ `tier install` configures 25 agent clients across JSON, TOML, YAML, and `SKILL.md` schemas. It
201
+ backs up every file it touches, merges instead of overwriting, supports `--dry-run` and
202
+ `--uninstall`, and validates the result with `tier doctor`.
203
+
204
+ <details>
205
+ <summary><b>Client list and config paths</b></summary>
206
+
207
+ | Client | Scope | Config |
208
+ |---|---|---|
209
+ | Claude Code | project / user | `.mcp.json` + `.claude/settings.json`, `~/.claude.json` |
210
+ | Claude Desktop | user | `claude_desktop_config.json` |
211
+ | Command Code | project / user | `.commandcode/mcp.json`, `~/.commandcode/mcp.json` |
212
+ | OpenCode | project / global | `opencode.json`, `~/.config/opencode/opencode.json` |
213
+ | OpenAI Codex CLI | project / user | `.codex/config.toml`, `~/.codex/config.toml` |
214
+ | Gemini CLI | project / user | `.gemini/settings.json` + `GEMINI.md` |
215
+ | Cursor | project / global | `.cursor/mcp.json`, `~/.cursor/mcp.json` |
216
+ | VS Code Copilot | project | `.vscode/mcp.json` |
217
+ | Windsurf | user | `~/.codeium/windsurf/mcp_config.json` |
218
+ | Roo Code / Cline | project | `.roo/mcp.json` |
219
+ | Trae | project | `.trae/mcp.json` |
220
+ | JetBrains Junie | project / user | `.junie/mcp/mcp.json`, `~/.junie/mcp/mcp.json` |
221
+ | Kiro | project | `.kiro/settings/mcp.json` |
222
+ | Warp | user | `~/.warp/.mcp.json` |
223
+ | Zed | user | `~/.config/zed/settings.json` (`context_servers`) |
224
+ | Continue.dev | project | `.continue/mcpServers/tier.yaml` |
225
+ | Agent Skills | project / user | `.agents/skills/tier/SKILL.md` |
226
+
227
+ Any other client can be configured with `--custom-config PATH --schema NAME`, and
228
+ `tier config-snippet` prints ready-to-copy JSON, TOML, YAML, and `SKILL.md` snippets plus native
229
+ CLI one-liners.
230
+
231
+ </details>
232
+
233
+ <details>
234
+ <summary><b>Optional extras</b></summary>
235
+
236
+ ```sh
237
+ uv tool install "tier-ctx[ui] @ git+https://github.com/000jd/tier" # rich terminal UI
238
+ uv tool install "tier-ctx[mcp] @ git+https://github.com/000jd/tier" # official MCP SDK
239
+ uv tool install "tier-ctx[treesitter] @ git+https://github.com/000jd/tier" # multi-language AST
240
+ uv tool install "tier-ctx[all] @ git+https://github.com/000jd/tier"
241
+ ```
242
+
243
+ - `[ui]` adds `rich` rendering for `tier install` and `tier doctor`.
244
+ - `[mcp]` adds the official SDK adapter (`tier-mcp-sdk`), Streamable HTTP, and MCP Inspector.
245
+ - `[treesitter]` adds Tree-sitter grammars for TypeScript, JavaScript, Go, Rust, C, C++, Java,
246
+ and Ruby. Without it the stdlib extractors are used, and repository maps are byte-identical.
247
+
248
+ </details>
249
+
250
+ ## Documentation
251
+
252
+ - [`docs/spec.md`](docs/spec.md) — the format, parser rules, and retrieval protocol
253
+ - [`ARCHITECTURE.md`](ARCHITECTURE.md) — module boundaries, layer flow, and invariants
254
+ - [`SKILL.md`](SKILL.md) — the canonical Agent Skill: entry point, CLI and MCP tables, working rules
255
+ - [`docs/cli.md`](docs/cli.md) — every command and flag
256
+ - [`docs/mcp.md`](docs/mcp.md) — the 12 MCP tools, one-turn workflow, and cache behaviour
257
+ - [`benchmarks/README.md`](benchmarks/README.md) — workload definitions and methodology
258
+ - [`CONTRIBUTING.md`](CONTRIBUTING.md) — development setup and extension guides
259
+ - [`CHANGELOG.md`](CHANGELOG.md) — release history
260
+
261
+ ## Limits
262
+
263
+ Only token counts, retrieval identifiers, and exact-slice coverage are measured — not LLM answer
264
+ accuracy. Claude's tokenizer is not public, so counts use OpenAI `o200k` via a persistent Node
265
+ worker when available, and a characters/4 estimate otherwise. `tier hook` treats its token budget
266
+ as a contract: it skips a payload only when it is provably within budget, otherwise it counts
267
+ exactly and verifies the output. `tier sync` trusts recorded mtime and size as a cache; use
268
+ `tier sync --rehash` after tooling that restores timestamps. JS/TS/Go/Rust symbol extraction is
269
+ heuristic without the `[treesitter]` extra.
270
+
271
+ ## License
272
+
273
+ MIT © 2026 000jd. See [LICENSE](LICENSE).
@@ -0,0 +1,252 @@
1
+ <div align="center">
2
+
3
+ # TIER
4
+
5
+ **Layered context for AI coding agents: a 4-layer document and repository format, a code graph
6
+ indexer, and a zero-dependency MCP server.**
7
+
8
+ [![CI](https://github.com/000jd/tier/actions/workflows/ci.yml/badge.svg)](.github/workflows/ci.yml)
9
+ [![PyPI](https://img.shields.io/badge/pypi-tier--ctx-blue)](https://pypi.org/project/tier-ctx/)
10
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white)](pyproject.toml)
11
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ `tier` keeps an agent from loading whole repositories and documents into its context. Every
18
+ document carries a small always-loadable index, one-line abstracts, structured bodies with symbol
19
+ signatures and dependency edges, and exact source-line ranges it can fetch on demand. A hybrid
20
+ retriever routes a question to the right section, an incremental repository map keeps fingerprints
21
+ and line ranges current, and a reverse-dependency graph answers what an edit affects.
22
+
23
+ The core is pure Python standard library: `dependencies = []`, no network calls, no telemetry.
24
+ It runs entirely offline on Python 3.10 and later. Optional extras add terminal styling, the
25
+ official MCP SDK adapter, and Tree-sitter grammars.
26
+
27
+ ## Installation
28
+
29
+ Zero-clone installs, in order of least commitment:
30
+
31
+ ```sh
32
+ uvx --from tier-ctx tier install # run the installer once, leave nothing installed
33
+ uv tool install tier-ctx # put `tier`, `tier-mcp`, and `tier-mcp-sdk` on PATH
34
+ pipx install tier-ctx # the same, where pipx is preferred
35
+ ```
36
+
37
+ Until the PyPI release is live, install from Git:
38
+
39
+ ```sh
40
+ uv tool install git+https://github.com/000jd/tier
41
+ uv tool install "tier-ctx[all] @ git+https://github.com/000jd/tier" # + rich UI, MCP SDK
42
+ ```
43
+
44
+ From a checkout, inside a virtual environment:
45
+
46
+ ```sh
47
+ git clone https://github.com/000jd/tier && cd tier
48
+ python3 -m venv .venv && . .venv/bin/activate
49
+ pip install -e ".[all]"
50
+ ```
51
+
52
+ > The distribution is named `tier-ctx`; the import package and console scripts are `tier`,
53
+ > `tier-mcp`, and `tier-mcp-sdk`. The bare PyPI name `tier` belongs to an unrelated package.
54
+
55
+ ## Example
56
+
57
+ An end-to-end session on a small project — install once, then one call per question:
58
+
59
+ ````console
60
+ $ tier install --clients claude-code --yes
61
+ Target: /home/me/myproject
62
+ Clients: claude-code
63
+ cache (.git/info/tier): /home/me/myproject/.git/info/tier/repo.tier (created)
64
+ Tokens: raw source 197 -> L0 130 (34.0% saved)
65
+ Instructions: /home/me/myproject/CLAUDE.md, /home/me/myproject/AGENTS.md
66
+
67
+ $ tier context . "how does the retry backoff work" --budget-tokens 800
68
+ ## Context: how does the retry backoff work
69
+
70
+ @src-http-client.py src/http/client.py
71
+ ? HTTP client with retry and backoff.; symbols: backoff_delay, request
72
+ |symbols[3]{kind,name,signature,lines}
73
+ function,backoff_delay,def backoff_delay(attempt: int) -> float,7-9
74
+ function,request,"def request(url: str, retries: int=DEFAULT_RETRIES)",12-19
75
+ function,_send,def _send(url: str),22-23
76
+ |calls[1]{caller,callee,module}
77
+ request,backoff_delay,.
78
+
79
+ @src-http-client.py#backoff_delay [L7-L9]
80
+ ```python
81
+ def backoff_delay(attempt: int) -> float:
82
+ """Exponential backoff, capped at 30 seconds."""
83
+ return min(2 ** attempt, 30.0)
84
+ ```
85
+
86
+ ## Impact: @src-http-client.py#backoff_delay
87
+ Direct dependents: @src-api-client.py
88
+ Transitive dependents: @src-api-client.py
89
+ Symbol callers: src/http/client.py#request [12-19]
90
+
91
+ $ tier impact src/http/client.py#backoff_delay
92
+ Impact target: @src-http-client.py
93
+ Direct dependents: @src-api-client.py
94
+ Transitive dependents: @src-api-client.py
95
+ Dependencies: none
96
+ Transitive dependencies: none
97
+ Symbol: src/http/client.py#backoff_delay
98
+ Symbol callers: src/http/client.py#request [12-19]
99
+ Symbol calls: none
100
+
101
+ $ tier slice src/http/client.py backoff_delay
102
+ @src-http-client.py#backoff_delay [L7-L9]
103
+ ```python
104
+ def backoff_delay(attempt: int) -> float:
105
+ """Exponential backoff, capped at 30 seconds."""
106
+ return min(2 ** attempt, 30.0)
107
+ ```
108
+ ````
109
+
110
+ ## How it works
111
+
112
+ TIER splits every document into four layers, and an agent reads only the ones it needs.
113
+
114
+ - **L0 — index.** Document metadata, global rules, and one line per section carrying that
115
+ section's token cost and rule count. Always loaded; a few hundred tokens.
116
+ - **L1 — abstracts.** A one-line `?` summary per section saying *when* to read it, folded into
117
+ the L0 index.
118
+ - **L2 — bodies.** Section contents; for codebases, a `|symbols` table with exact
119
+ `[start-end]` line ranges and `>` edges to local dependencies.
120
+ - **L3 — slices.** Exact source lines for one symbol, fetched by name.
121
+
122
+ `tier_context` collapses the whole loop into one call: resolve or build the repository index,
123
+ route the query with the hybrid retriever, match symbol names, then pack L2 bodies, L3 slices,
124
+ and a dependency summary until the token budget is spent. The granular commands remain available
125
+ when you need a specific section id or symbol.
126
+
127
+ ## Architecture highlights
128
+
129
+ **Header-once tables and indented key/value trees.** A record set is a header plus exactly N CSV
130
+ rows, and nested data is a two-space-indented tree. Both keep the schema and drop the repeated
131
+ punctuation that JSON and Markdown tables spend tokens on.
132
+
133
+ **Deterministic line-start sigils.** Every line is classified by its first character: `%` header,
134
+ `@` section, `?` abstract, `!` rule, `=` key/value, `|` counted table, `>` reference, `$` command.
135
+ Fenced code, untrusted blocks, and table rows are opaque, so no sigil inside them is reinterpreted.
136
+
137
+ **Untrusted content guards.** Text from the outside world is wrapped in `<<<source #guard ...
138
+ >>>guard`. The guards are chosen so that the payload cannot contain its own terminator, which makes
139
+ embedded instructions, fake headers, and rule sigils inert data.
140
+
141
+ **Stateful session deduplication.** A section or source slice already delivered in the conversation
142
+ is replaced by a one-line stub on the next request. `sync` evicts exactly the sections whose files
143
+ changed, and their slices.
144
+
145
+ **Symbol-level blast radius.** Repository maps record `>` edges between modules and a `|calls`
146
+ table of caller/callee pairs. `tier impact` reports file-level importers and, given
147
+ `module#symbol`, the exact functions that call it. `tier_context` filters `|calls` tables to the
148
+ 1-hop neighbourhood of the sections it returns; pass `include_calls="all"` to see every edge.
149
+
150
+ **Invisible repository cache.** The map is a derived artifact, so it lives in
151
+ `.git/info/tier/repo.tier` inside a worktree (which Git ignores) or in a user cache directory
152
+ outside it. `.git` is followed when it is a pointer file rather than a directory, so linked
153
+ worktrees and submodules resolve to their own git directory. A tracked `repo.tier` is still
154
+ honoured when one exists. Nothing is written into your working tree, so `git status` stays clean.
155
+
156
+ **Hybrid search with precomputed IDF.** BM25-style term scoring over split identifiers, a compact
157
+ synonym map, character 3-gram fallback for typos, and navigation priors. Document frequencies are
158
+ computed once per query, which keeps a search over 800 sections near 200 ms with no index to build.
159
+
160
+ ## Performance
161
+
162
+ Measured with the `o200k_base` tokenizer. These are token counts and retrieval hit rates, not LLM
163
+ answer accuracy. Methodology and reproduction steps are in
164
+ [`benchmarks/README.md`](benchmarks/README.md).
165
+
166
+ | Workload | Measure | Result |
167
+ |---|---|---|
168
+ | Repository overview | raw source → full map → L0 → L0 + one module | 72,859 → 14,375 → 828 → 1,784 tokens (−98%) |
169
+ | End-to-end 4-layer workflow | index, find, L2, L3 slices, impact + sync | 5,003 tokens (−93.1%), 3/3 exact slices |
170
+ | 36-file polyglot repository | surgical L0 + target L2 + 7 slices | 3,008 vs 8,249 tokens (−64%), 116/116 symbols |
171
+ | 197-section blind retrieval | 15 queries | 15/15 hit@1, mean top-1 fetch 134 tokens |
172
+
173
+ [`benchmarks/BENCH.txt`](benchmarks/BENCH.txt) carries the full Track A–I breakdown, including the
174
+ record-encoding and nested-config tracks, the per-query retrieval logs, and the raw output behind
175
+ every row above.
176
+
177
+ ## Supported clients
178
+
179
+ `tier install` configures 25 agent clients across JSON, TOML, YAML, and `SKILL.md` schemas. It
180
+ backs up every file it touches, merges instead of overwriting, supports `--dry-run` and
181
+ `--uninstall`, and validates the result with `tier doctor`.
182
+
183
+ <details>
184
+ <summary><b>Client list and config paths</b></summary>
185
+
186
+ | Client | Scope | Config |
187
+ |---|---|---|
188
+ | Claude Code | project / user | `.mcp.json` + `.claude/settings.json`, `~/.claude.json` |
189
+ | Claude Desktop | user | `claude_desktop_config.json` |
190
+ | Command Code | project / user | `.commandcode/mcp.json`, `~/.commandcode/mcp.json` |
191
+ | OpenCode | project / global | `opencode.json`, `~/.config/opencode/opencode.json` |
192
+ | OpenAI Codex CLI | project / user | `.codex/config.toml`, `~/.codex/config.toml` |
193
+ | Gemini CLI | project / user | `.gemini/settings.json` + `GEMINI.md` |
194
+ | Cursor | project / global | `.cursor/mcp.json`, `~/.cursor/mcp.json` |
195
+ | VS Code Copilot | project | `.vscode/mcp.json` |
196
+ | Windsurf | user | `~/.codeium/windsurf/mcp_config.json` |
197
+ | Roo Code / Cline | project | `.roo/mcp.json` |
198
+ | Trae | project | `.trae/mcp.json` |
199
+ | JetBrains Junie | project / user | `.junie/mcp/mcp.json`, `~/.junie/mcp/mcp.json` |
200
+ | Kiro | project | `.kiro/settings/mcp.json` |
201
+ | Warp | user | `~/.warp/.mcp.json` |
202
+ | Zed | user | `~/.config/zed/settings.json` (`context_servers`) |
203
+ | Continue.dev | project | `.continue/mcpServers/tier.yaml` |
204
+ | Agent Skills | project / user | `.agents/skills/tier/SKILL.md` |
205
+
206
+ Any other client can be configured with `--custom-config PATH --schema NAME`, and
207
+ `tier config-snippet` prints ready-to-copy JSON, TOML, YAML, and `SKILL.md` snippets plus native
208
+ CLI one-liners.
209
+
210
+ </details>
211
+
212
+ <details>
213
+ <summary><b>Optional extras</b></summary>
214
+
215
+ ```sh
216
+ uv tool install "tier-ctx[ui] @ git+https://github.com/000jd/tier" # rich terminal UI
217
+ uv tool install "tier-ctx[mcp] @ git+https://github.com/000jd/tier" # official MCP SDK
218
+ uv tool install "tier-ctx[treesitter] @ git+https://github.com/000jd/tier" # multi-language AST
219
+ uv tool install "tier-ctx[all] @ git+https://github.com/000jd/tier"
220
+ ```
221
+
222
+ - `[ui]` adds `rich` rendering for `tier install` and `tier doctor`.
223
+ - `[mcp]` adds the official SDK adapter (`tier-mcp-sdk`), Streamable HTTP, and MCP Inspector.
224
+ - `[treesitter]` adds Tree-sitter grammars for TypeScript, JavaScript, Go, Rust, C, C++, Java,
225
+ and Ruby. Without it the stdlib extractors are used, and repository maps are byte-identical.
226
+
227
+ </details>
228
+
229
+ ## Documentation
230
+
231
+ - [`docs/spec.md`](docs/spec.md) — the format, parser rules, and retrieval protocol
232
+ - [`ARCHITECTURE.md`](ARCHITECTURE.md) — module boundaries, layer flow, and invariants
233
+ - [`SKILL.md`](SKILL.md) — the canonical Agent Skill: entry point, CLI and MCP tables, working rules
234
+ - [`docs/cli.md`](docs/cli.md) — every command and flag
235
+ - [`docs/mcp.md`](docs/mcp.md) — the 12 MCP tools, one-turn workflow, and cache behaviour
236
+ - [`benchmarks/README.md`](benchmarks/README.md) — workload definitions and methodology
237
+ - [`CONTRIBUTING.md`](CONTRIBUTING.md) — development setup and extension guides
238
+ - [`CHANGELOG.md`](CHANGELOG.md) — release history
239
+
240
+ ## Limits
241
+
242
+ Only token counts, retrieval identifiers, and exact-slice coverage are measured — not LLM answer
243
+ accuracy. Claude's tokenizer is not public, so counts use OpenAI `o200k` via a persistent Node
244
+ worker when available, and a characters/4 estimate otherwise. `tier hook` treats its token budget
245
+ as a contract: it skips a payload only when it is provably within budget, otherwise it counts
246
+ exactly and verifies the output. `tier sync` trusts recorded mtime and size as a cache; use
247
+ `tier sync --rehash` after tooling that restores timestamps. JS/TS/Go/Rust symbol extraction is
248
+ heuristic without the `[treesitter]` extra.
249
+
250
+ ## License
251
+
252
+ MIT © 2026 000jd. See [LICENSE](LICENSE).
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tier-ctx"
7
+ version = "1.2.1"
8
+ description = "TIER: layered context, repository graphs, code slicing, and agent memory"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ authors = [{ name = "000jd" }]
12
+ license = { text = "MIT" }
13
+ dependencies = []
14
+
15
+ [project.optional-dependencies]
16
+ ui = ["rich>=13.0"]
17
+ mcp = ["mcp>=2.0"]
18
+ treesitter = ["tree-sitter-language-pack>=0.7.0"]
19
+ all = ["rich>=13.0", "mcp>=2.0", "tree-sitter-language-pack>=0.7.0"]
20
+
21
+ [project.scripts]
22
+ tier = "tier.cli:main"
23
+ tier-mcp = "tier.mcp.server:main"
24
+ tier-mcp-sdk = "tier.mcp.sdk_server:main"
25
+
26
+ [tool.setuptools]
27
+ package-dir = {"" = "src"}
28
+
29
+ [tool.setuptools.packages.find]
30
+ where = ["src"]
31
+ include = ["tier*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,53 @@
1
+ """TIER: layered context, repository graphs, code slicing, and agent memory."""
2
+ from __future__ import annotations
3
+
4
+ from .models import (
5
+ VERSION, Doc, Section, SIGIL_CHARS, SEC_RE, HDR_RE, TABLE_RE, DATA_OPEN_RE,
6
+ RULE_START, STOP, SHELL_LANGS, TABLE_MODES, _W, _atomic_write, _clip, _inside,
7
+ _read_text, _table_count,
8
+ )
9
+ from .tokens import count_tokens
10
+ from .parser import (
11
+ _csv_cells, _data_closes, _data_open, _kv_split, _live_lines, _load, _parse_kv,
12
+ _render_table, _repo_file_meta, _table_rows, dumps, is_repo_doc, nodes, parse,
13
+ render_lines, render_section, to_obj, wrap_untrusted,
14
+ )
15
+ from .lint import lint
16
+ from .converter import (
17
+ _auto_abstract, _clip as _converter_clip, _csv_row, _esc, _json_body, _json_cell,
18
+ _json_kv_lines, _json_scalar, _make_id, _md_cells, _one_line_text, _records_table,
19
+ _ref_topics, _table_name, from_json, from_md, from_payload, to_md,
20
+ )
21
+ from .retrieval import (
22
+ QSTOP, SYNONYMS, Session, _find_legacy, _index_tokens, _is_navigation_section,
23
+ _is_test_module, _norm, _query_terms, _rule_count, _synonym_map, _trigram_sim,
24
+ _trigrams, find, get, index, resolve, split_identifier,
25
+ )
26
+ from .repo import (
27
+ JS_CONTROL, LANG_BY_EXT, REPO_ENTRY_NAMES, REPO_SKIP_DIRS, REPO_SOURCE_EXTS,
28
+ _brace_end, _build_graph, _changed_symbols, _extract_symbols, _git_changed_paths,
29
+ _go_module, _go_symbols, _js_arrow_name, _js_expr_end, _js_rhs_arrow, _js_symbols,
30
+ _leading_comment, _py_module_name, _py_symbols, _reachable, _repo_add_deps, _repo_id,
31
+ _repo_info, _repo_section, _repo_summary, _resolve_go_imports, _resolve_impact_target,
32
+ _resolve_js_imports, _resolve_module, _resolve_py_imports, _resolve_rust_mods,
33
+ _rust_symbols, _sha256, _sig_line, _slice_range, _strip_code_strings, _symbol_rows,
34
+ _symbol_table, _top_symbol_names, from_repo, impact, render_impact, repo_source_files,
35
+ slice, slice_symbols, sync_repo,
36
+ )
37
+ from .memory import _validate_section_body, remember
38
+ from .pipe import (
39
+ LOG_CMD_RE, LOG_ERR_RE, LOG_WARN_RE, _fit_text, _log_shape, _text_fields, _tokens,
40
+ detect_stream_format, from_stream, hook_process, log_doc, pipe_compress,
41
+ )
42
+ from .plugin import (
43
+ TIER_BEGIN, TIER_END, _hook_commands, _looks_like_tier_hook, _merge_hook_settings,
44
+ _plugin_instructions, _write_marked_instructions, init_plugin,
45
+ )
46
+
47
+ __version__ = VERSION
48
+ __all__ = [
49
+ "VERSION", "Doc", "Section", "parse", "dumps", "index", "find", "get", "slice",
50
+ "slice_symbols", "impact", "sync_repo", "from_repo", "remember", "Session",
51
+ "wrap_untrusted", "from_md", "from_json", "from_payload", "to_md", "lint", "nodes",
52
+ "count_tokens", "pipe_compress", "hook_process", "init_plugin",
53
+ ]
@@ -0,0 +1,5 @@
1
+ """Enable `python -m tier`."""
2
+ from .cli import main
3
+
4
+ if __name__ == "__main__":
5
+ raise SystemExit(main())