lightfoot 1.0.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.
- lightfoot-1.0.0/LICENSE +21 -0
- lightfoot-1.0.0/PKG-INFO +196 -0
- lightfoot-1.0.0/README.md +161 -0
- lightfoot-1.0.0/lightfoot/__init__.py +3 -0
- lightfoot-1.0.0/lightfoot/__main__.py +7 -0
- lightfoot-1.0.0/lightfoot/adapters/__init__.py +49 -0
- lightfoot-1.0.0/lightfoot/adapters/anthropic.py +259 -0
- lightfoot-1.0.0/lightfoot/adapters/base.py +224 -0
- lightfoot-1.0.0/lightfoot/adapters/chat.py +190 -0
- lightfoot-1.0.0/lightfoot/adapters/gemini.py +195 -0
- lightfoot-1.0.0/lightfoot/adapters/responses.py +201 -0
- lightfoot-1.0.0/lightfoot/agentplugins.py +151 -0
- lightfoot-1.0.0/lightfoot/agentskills.py +75 -0
- lightfoot-1.0.0/lightfoot/audit.py +146 -0
- lightfoot-1.0.0/lightfoot/cachesim.py +192 -0
- lightfoot-1.0.0/lightfoot/capture.py +109 -0
- lightfoot-1.0.0/lightfoot/cli.py +674 -0
- lightfoot-1.0.0/lightfoot/codexlog.py +197 -0
- lightfoot-1.0.0/lightfoot/config.py +386 -0
- lightfoot-1.0.0/lightfoot/dashboard.py +312 -0
- lightfoot-1.0.0/lightfoot/data/models.toml +165 -0
- lightfoot-1.0.0/lightfoot/data/skills/lightfoot-condensed-context/SKILL.md +21 -0
- lightfoot-1.0.0/lightfoot/data/skills/lightfoot-stats/SKILL.md +10 -0
- lightfoot-1.0.0/lightfoot/data/skills/lightfoot-why/SKILL.md +10 -0
- lightfoot-1.0.0/lightfoot/estimate.py +665 -0
- lightfoot-1.0.0/lightfoot/evaluate.py +462 -0
- lightfoot-1.0.0/lightfoot/fastjson.py +38 -0
- lightfoot-1.0.0/lightfoot/geminilog.py +286 -0
- lightfoot-1.0.0/lightfoot/guards.py +101 -0
- lightfoot-1.0.0/lightfoot/handoff.py +377 -0
- lightfoot-1.0.0/lightfoot/hookmode.py +243 -0
- lightfoot-1.0.0/lightfoot/idlehandoff.py +206 -0
- lightfoot-1.0.0/lightfoot/images.py +117 -0
- lightfoot-1.0.0/lightfoot/ingest.py +235 -0
- lightfoot-1.0.0/lightfoot/integrate.py +145 -0
- lightfoot-1.0.0/lightfoot/integrations.py +54 -0
- lightfoot-1.0.0/lightfoot/launch.py +589 -0
- lightfoot-1.0.0/lightfoot/maintenance.py +144 -0
- lightfoot-1.0.0/lightfoot/opencodehook.py +136 -0
- lightfoot-1.0.0/lightfoot/opencodelog.py +242 -0
- lightfoot-1.0.0/lightfoot/pricing.py +278 -0
- lightfoot-1.0.0/lightfoot/profiles.py +352 -0
- lightfoot-1.0.0/lightfoot/providers.py +136 -0
- lightfoot-1.0.0/lightfoot/prune.py +626 -0
- lightfoot-1.0.0/lightfoot/reports.py +612 -0
- lightfoot-1.0.0/lightfoot/server.py +834 -0
- lightfoot-1.0.0/lightfoot/statusline.py +298 -0
- lightfoot-1.0.0/lightfoot/store.py +587 -0
- lightfoot-1.0.0/lightfoot/subagents.py +103 -0
- lightfoot-1.0.0/lightfoot/support.py +92 -0
- lightfoot-1.0.0/lightfoot/text.py +276 -0
- lightfoot-1.0.0/lightfoot/transform.py +781 -0
- lightfoot-1.0.0/lightfoot/usage.py +219 -0
- lightfoot-1.0.0/lightfoot/validate.py +120 -0
- lightfoot-1.0.0/lightfoot/why.py +144 -0
- lightfoot-1.0.0/lightfoot.egg-info/PKG-INFO +196 -0
- lightfoot-1.0.0/lightfoot.egg-info/SOURCES.txt +104 -0
- lightfoot-1.0.0/lightfoot.egg-info/dependency_links.txt +1 -0
- lightfoot-1.0.0/lightfoot.egg-info/entry_points.txt +2 -0
- lightfoot-1.0.0/lightfoot.egg-info/requires.txt +12 -0
- lightfoot-1.0.0/lightfoot.egg-info/top_level.txt +1 -0
- lightfoot-1.0.0/pyproject.toml +86 -0
- lightfoot-1.0.0/setup.cfg +4 -0
- lightfoot-1.0.0/tests/test_agentplugins.py +63 -0
- lightfoot-1.0.0/tests/test_agentskills.py +60 -0
- lightfoot-1.0.0/tests/test_audit.py +36 -0
- lightfoot-1.0.0/tests/test_bench.py +117 -0
- lightfoot-1.0.0/tests/test_cachesim.py +54 -0
- lightfoot-1.0.0/tests/test_capture.py +71 -0
- lightfoot-1.0.0/tests/test_chat.py +156 -0
- lightfoot-1.0.0/tests/test_cli.py +202 -0
- lightfoot-1.0.0/tests/test_cline.py +222 -0
- lightfoot-1.0.0/tests/test_codexlog.py +73 -0
- lightfoot-1.0.0/tests/test_compaction.py +287 -0
- lightfoot-1.0.0/tests/test_config.py +83 -0
- lightfoot-1.0.0/tests/test_dashboard.py +71 -0
- lightfoot-1.0.0/tests/test_fastjson.py +36 -0
- lightfoot-1.0.0/tests/test_gemini.py +317 -0
- lightfoot-1.0.0/tests/test_geminilog.py +131 -0
- lightfoot-1.0.0/tests/test_guards.py +130 -0
- lightfoot-1.0.0/tests/test_handoff_eval.py +173 -0
- lightfoot-1.0.0/tests/test_hook_watch.py +71 -0
- lightfoot-1.0.0/tests/test_hookmode.py +142 -0
- lightfoot-1.0.0/tests/test_idlehandoff.py +126 -0
- lightfoot-1.0.0/tests/test_images.py +198 -0
- lightfoot-1.0.0/tests/test_integrate.py +87 -0
- lightfoot-1.0.0/tests/test_launch.py +149 -0
- lightfoot-1.0.0/tests/test_maintenance.py +208 -0
- lightfoot-1.0.0/tests/test_models_data.py +59 -0
- lightfoot-1.0.0/tests/test_opencode.py +90 -0
- lightfoot-1.0.0/tests/test_opencodehook.py +92 -0
- lightfoot-1.0.0/tests/test_opencodelog.py +160 -0
- lightfoot-1.0.0/tests/test_plugin.py +28 -0
- lightfoot-1.0.0/tests/test_properties.py +149 -0
- lightfoot-1.0.0/tests/test_providers.py +50 -0
- lightfoot-1.0.0/tests/test_prune.py +389 -0
- lightfoot-1.0.0/tests/test_release_manifests.py +89 -0
- lightfoot-1.0.0/tests/test_reports.py +22 -0
- lightfoot-1.0.0/tests/test_responses.py +327 -0
- lightfoot-1.0.0/tests/test_server.py +263 -0
- lightfoot-1.0.0/tests/test_statusline.py +169 -0
- lightfoot-1.0.0/tests/test_subagents.py +41 -0
- lightfoot-1.0.0/tests/test_support.py +23 -0
- lightfoot-1.0.0/tests/test_text.py +158 -0
- lightfoot-1.0.0/tests/test_transform.py +473 -0
- lightfoot-1.0.0/tests/test_why.py +83 -0
lightfoot-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Miska
|
|
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.
|
lightfoot-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lightfoot
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A local, cache-aware token-saving proxy for coding agents
|
|
5
|
+
Author: Miska
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/miska-voutilainen/lightfoot
|
|
8
|
+
Project-URL: Documentation, https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md
|
|
9
|
+
Project-URL: Changelog, https://github.com/miska-voutilainen/lightfoot/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Issues, https://github.com/miska-voutilainen/lightfoot/issues
|
|
11
|
+
Keywords: coding-agents,claude-code,codex,gemini-cli,opencode,aider,proxy,prompt-caching,tokens,llm
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Software Development
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: starlette>=0.37
|
|
26
|
+
Requires-Dist: uvicorn>=0.29
|
|
27
|
+
Requires-Dist: httpx>=0.27
|
|
28
|
+
Requires-Dist: orjson>=3.10; platform_python_implementation == "CPython"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
33
|
+
Requires-Dist: hypothesis>=6.100; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
<h1 align="center">Lightfoot V1</h1>
|
|
37
|
+
|
|
38
|
+
<p align="center">
|
|
39
|
+
<a href="https://pypi.org/project/lightfoot/"><img src="https://img.shields.io/pypi/v/lightfoot.svg" alt="PyPI"/></a>
|
|
40
|
+
<a href="https://github.com/miska-voutilainen/lightfoot/actions/workflows/ci.yml"><img src="https://github.com/miska-voutilainen/lightfoot/actions/workflows/ci.yml/badge.svg" alt="CI"/></a>
|
|
41
|
+
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+"/></a>
|
|
42
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License: MIT"/></a>
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<p align="center">
|
|
46
|
+
<b>Long coding-agent sessions, cheaper. Without making them worse.</b>
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
Every turn of an agent session re-sends the whole conversation, and on long sessions most of the bill is the model re-reading it from the cache. Lightfoot is a local proxy between your agent and the model API that keeps that conversation lean. Start your agent through it (`lightfoot claude`, `lightfoot codex`, `lightfoot run -- <command>`) and nothing else changes.
|
|
50
|
+
|
|
51
|
+
- **Never mid-task.** Old turns are condensed only at your next prompt, past 200k tokens. Work in progress is never cut into.
|
|
52
|
+
- **Nothing is lost.** Everything condensed is saved under `.lightfoot/`, and the summary says where to find it.
|
|
53
|
+
- **Free to run.** No model calls. The summary is built from the conversation itself, and nothing leaves your machine except the request your agent was already sending.
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
Paste this into your coding agent. It asks before installing anything optional, and shows each command before running it ([the instructions it follows](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/agent-install.md)):
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
Install Lightfoot for me: run `curl -fsSL https://raw.githubusercontent.com/miska-voutilainen/lightfoot/main/docs/agent-install.md`, then follow those instructions step by step.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Or install it yourself.** Needs Python 3.11+ and uv (or pipx):
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
uv tool install lightfoot # or: pipx install lightfoot
|
|
67
|
+
lightfoot estimate # what it would have saved on your past sessions (offline, free)
|
|
68
|
+
lightfoot claude # start your agent through Lightfoot; every argument passes through
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It starts in **shadow mode**: it measures what it would save and changes nothing. When `lightfoot stats` looks good, `lightfoot shadow off` turns the savings on. `lightfoot off` stops them immediately.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## See it in action
|
|
76
|
+
|
|
77
|
+
`lightfoot estimate` replays your existing session transcripts offline and prices them with and without Lightfoot. A real run on 139 sessions (8,646 API calls, API prices as of 2026-10-25):
|
|
78
|
+
|
|
79
|
+
| Where the cost went | Cost | Share |
|
|
80
|
+
| --- | ---: | ---: |
|
|
81
|
+
| Cache reads | $560.08 | 58.1% |
|
|
82
|
+
| Cache writes | $248.76 | 25.8% |
|
|
83
|
+
| Output | $155.75 | 16.1% |
|
|
84
|
+
| Uncached input | $0.14 | 0.0% |
|
|
85
|
+
| Total | $964.72 | 100% |
|
|
86
|
+
|
|
87
|
+
58% of the money went to re-reading the conversation from the cache. That is the part Lightfoot shrinks: with it, the same sessions would have cost **$706.88**, a saving of **26.7%**. The longest sessions saved 35 to 46%; short sessions that never pass 200k tokens are left mostly alone and save close to nothing.
|
|
88
|
+
|
|
89
|
+
It is an estimate. Shadow mode measures the real thing on your own work, and `lightfoot eval` runs a paired comparison.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## What it does
|
|
94
|
+
|
|
95
|
+
Your agent sends its request to Lightfoot on your machine. Lightfoot condenses it, validates the result against the original, and forwards it to the model API. The response comes back unchanged.
|
|
96
|
+
|
|
97
|
+
| Rule | What it does |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| **Old-turn pruning** | Past 200k tokens, at your next prompt, the oldest turns become one summary. Your requests stay verbatim. |
|
|
100
|
+
| **Noise stripping** | ANSI codes, terminal redraws, progress bars and repeated lines go. |
|
|
101
|
+
| **Large-output trimming** | Output over ~4k tokens keeps its head, tail and every error line. The rest is saved to a file. |
|
|
102
|
+
| **JSON minification** | Pretty-printed JSON loses only its whitespace, checked by re-parsing. |
|
|
103
|
+
| **Stale reads and searches** | Superseded file reads and repeated searches become one-line stubs. |
|
|
104
|
+
| **Old images** | All but the 3 newest screenshots become a stub. Each image is saved to a file. |
|
|
105
|
+
|
|
106
|
+
Each rewrite happens once and is then replayed byte for byte on every later turn, so the prompt cache stays warm. Almost all of the saving comes from pruning old turns.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## What stays intact
|
|
111
|
+
|
|
112
|
+
- **Your words.** Your first message, your last 3 prompts with all their work, and at least the latest 100k tokens are kept as they were.
|
|
113
|
+
- **Fail-safe.** If a rewrite fails validation for any reason, your original request goes out instead.
|
|
114
|
+
- **Measured.** `lightfoot stats` counts how often the agent goes back for condensed content, and flags rules that cut too much.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Supported agents
|
|
119
|
+
|
|
120
|
+
| Agent | Level | Status |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| Claude Code | 3 · model summaries | Supported |
|
|
123
|
+
| Apps on the Claude Agent SDK | 2 · history edits | Supported |
|
|
124
|
+
| OpenAI Codex CLI | 0 · measure | Experimental |
|
|
125
|
+
| opencode | 0 · measure | Experimental |
|
|
126
|
+
| Gemini CLI | 0 · measure | Experimental, API-key auth only |
|
|
127
|
+
| Cline | wired | Experimental |
|
|
128
|
+
| Roo Code | wired | Experimental (project archived) |
|
|
129
|
+
| Aider | 0 · measure | Measured only |
|
|
130
|
+
| Other tools | wired | Experimental, via `lightfoot run -- <command>` |
|
|
131
|
+
| Cursor, Windsurf | - | Not possible: requests leave from their servers |
|
|
132
|
+
|
|
133
|
+
The level says how much is proven for each agent, from least to most: `wired` (built from its source, unit-tested) > `0 · measure` (its real traffic parsed) > `1 · output rules` > `2 · history edits` > `3 · model summaries` > `certified` (a passing paired eval). Experimental agents stay in shadow mode unless started with `--live --experimental`. [Details per agent](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md#supported-agents).
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Common commands
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
lightfoot claude # start an agent through Lightfoot (also: codex, opencode, gemini, aider)
|
|
141
|
+
lightfoot run -- <command> # any other tool that reads a base-URL variable
|
|
142
|
+
lightfoot estimate # what it would have saved on your past sessions
|
|
143
|
+
lightfoot stats # cost, savings and rule health per session
|
|
144
|
+
lightfoot why # what was condensed in a session, and where the full text is
|
|
145
|
+
lightfoot dashboard # a local report page
|
|
146
|
+
lightfoot shadow off # start saving (shadow on goes back to measuring)
|
|
147
|
+
lightfoot off # kill switch, immediate (lightfoot on resumes)
|
|
148
|
+
lightfoot doctor # check the setup
|
|
149
|
+
lightfoot plugins install --agent gemini # Lightfoot's extension for Gemini CLI (or --agent codex)
|
|
150
|
+
lightfoot skills install # the same guidance as skills, e.g. for opencode
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Resume sessions through Lightfoot too (`lightfoot claude --resume`); resuming without it re-sends the history uncondensed and rewrites the cache once. Hook mode (no proxy, for Claude Code and opencode), the Claude Code plugin and status line, every setting, and troubleshooting: **[the user guide](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md)**.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Privacy
|
|
158
|
+
|
|
159
|
+
- **Local only.** Listens on 127.0.0.1. Requests with other Host headers, and requests from browsers, are refused.
|
|
160
|
+
- **Your credentials** are forwarded unchanged and never written anywhere. With a subscription login, Lightfoot sends no requests of its own.
|
|
161
|
+
- **Project files can't take over.** A repository's `.lightfoot/config.toml` can't redirect your requests or run commands.
|
|
162
|
+
- **Retention.** Stored content is deleted 30 days after a session's last use. The cost ledger holds only token counts.
|
|
163
|
+
- **No telemetry**, no usage tracking, no analytics.
|
|
164
|
+
|
|
165
|
+
It uses about 50 MB of memory and almost no CPU when idle; a turn of a long session costs it a few tens of milliseconds. Works with API keys and with Pro and Max subscriptions ([what that means](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md#pro-and-max-subscriptions)).
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Works well with Graphify and Obsidian
|
|
170
|
+
|
|
171
|
+
Both are optional, detected when present, and never installed unless you ask.
|
|
172
|
+
|
|
173
|
+
- **[Graphify](https://github.com/Graphify-Labs/graphify)** cuts the tokens spent *finding* code. Lightfoot points trimmed searches at `graphify-out/GRAPH_REPORT.md` and drops repeated graph queries.
|
|
174
|
+
- **[Obsidian](https://obsidian.md)** cuts the tokens spent *re-establishing* context. Lightfoot writes a handoff note (what's done, decisions, open threads) into your vault when a session ends.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Learn more
|
|
179
|
+
|
|
180
|
+
- [User guide](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md): every command and setting, agents, subscriptions, troubleshooting, uninstall
|
|
181
|
+
- [Architecture](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/architecture.md): exactly what Lightfoot does to a request, and why
|
|
182
|
+
- [Comparison](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/comparison.md): how it differs from other token-saving tools
|
|
183
|
+
- [Development](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/development.md): set up, test, measure, release
|
|
184
|
+
- [Security](https://github.com/miska-voutilainen/lightfoot/blob/main/SECURITY.md): guarantees, and how to report a problem
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Contributing
|
|
189
|
+
|
|
190
|
+
Contributions are welcome. See **[CONTRIBUTING.md](https://github.com/miska-voutilainen/lightfoot/blob/main/CONTRIBUTING.md)** for the setup and the git workflow.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
[MIT](https://github.com/miska-voutilainen/lightfoot/blob/main/LICENSE). Lightfoot is an independent project, not affiliated with or endorsed by Anthropic, OpenAI, Google, Graphify or Obsidian.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<h1 align="center">Lightfoot V1</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://pypi.org/project/lightfoot/"><img src="https://img.shields.io/pypi/v/lightfoot.svg" alt="PyPI"/></a>
|
|
5
|
+
<a href="https://github.com/miska-voutilainen/lightfoot/actions/workflows/ci.yml"><img src="https://github.com/miska-voutilainen/lightfoot/actions/workflows/ci.yml/badge.svg" alt="CI"/></a>
|
|
6
|
+
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+"/></a>
|
|
7
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License: MIT"/></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<b>Long coding-agent sessions, cheaper. Without making them worse.</b>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
Every turn of an agent session re-sends the whole conversation, and on long sessions most of the bill is the model re-reading it from the cache. Lightfoot is a local proxy between your agent and the model API that keeps that conversation lean. Start your agent through it (`lightfoot claude`, `lightfoot codex`, `lightfoot run -- <command>`) and nothing else changes.
|
|
15
|
+
|
|
16
|
+
- **Never mid-task.** Old turns are condensed only at your next prompt, past 200k tokens. Work in progress is never cut into.
|
|
17
|
+
- **Nothing is lost.** Everything condensed is saved under `.lightfoot/`, and the summary says where to find it.
|
|
18
|
+
- **Free to run.** No model calls. The summary is built from the conversation itself, and nothing leaves your machine except the request your agent was already sending.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
Paste this into your coding agent. It asks before installing anything optional, and shows each command before running it ([the instructions it follows](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/agent-install.md)):
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
Install Lightfoot for me: run `curl -fsSL https://raw.githubusercontent.com/miska-voutilainen/lightfoot/main/docs/agent-install.md`, then follow those instructions step by step.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Or install it yourself.** Needs Python 3.11+ and uv (or pipx):
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
uv tool install lightfoot # or: pipx install lightfoot
|
|
32
|
+
lightfoot estimate # what it would have saved on your past sessions (offline, free)
|
|
33
|
+
lightfoot claude # start your agent through Lightfoot; every argument passes through
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
It starts in **shadow mode**: it measures what it would save and changes nothing. When `lightfoot stats` looks good, `lightfoot shadow off` turns the savings on. `lightfoot off` stops them immediately.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## See it in action
|
|
41
|
+
|
|
42
|
+
`lightfoot estimate` replays your existing session transcripts offline and prices them with and without Lightfoot. A real run on 139 sessions (8,646 API calls, API prices as of 2026-10-25):
|
|
43
|
+
|
|
44
|
+
| Where the cost went | Cost | Share |
|
|
45
|
+
| --- | ---: | ---: |
|
|
46
|
+
| Cache reads | $560.08 | 58.1% |
|
|
47
|
+
| Cache writes | $248.76 | 25.8% |
|
|
48
|
+
| Output | $155.75 | 16.1% |
|
|
49
|
+
| Uncached input | $0.14 | 0.0% |
|
|
50
|
+
| Total | $964.72 | 100% |
|
|
51
|
+
|
|
52
|
+
58% of the money went to re-reading the conversation from the cache. That is the part Lightfoot shrinks: with it, the same sessions would have cost **$706.88**, a saving of **26.7%**. The longest sessions saved 35 to 46%; short sessions that never pass 200k tokens are left mostly alone and save close to nothing.
|
|
53
|
+
|
|
54
|
+
It is an estimate. Shadow mode measures the real thing on your own work, and `lightfoot eval` runs a paired comparison.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## What it does
|
|
59
|
+
|
|
60
|
+
Your agent sends its request to Lightfoot on your machine. Lightfoot condenses it, validates the result against the original, and forwards it to the model API. The response comes back unchanged.
|
|
61
|
+
|
|
62
|
+
| Rule | What it does |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| **Old-turn pruning** | Past 200k tokens, at your next prompt, the oldest turns become one summary. Your requests stay verbatim. |
|
|
65
|
+
| **Noise stripping** | ANSI codes, terminal redraws, progress bars and repeated lines go. |
|
|
66
|
+
| **Large-output trimming** | Output over ~4k tokens keeps its head, tail and every error line. The rest is saved to a file. |
|
|
67
|
+
| **JSON minification** | Pretty-printed JSON loses only its whitespace, checked by re-parsing. |
|
|
68
|
+
| **Stale reads and searches** | Superseded file reads and repeated searches become one-line stubs. |
|
|
69
|
+
| **Old images** | All but the 3 newest screenshots become a stub. Each image is saved to a file. |
|
|
70
|
+
|
|
71
|
+
Each rewrite happens once and is then replayed byte for byte on every later turn, so the prompt cache stays warm. Almost all of the saving comes from pruning old turns.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## What stays intact
|
|
76
|
+
|
|
77
|
+
- **Your words.** Your first message, your last 3 prompts with all their work, and at least the latest 100k tokens are kept as they were.
|
|
78
|
+
- **Fail-safe.** If a rewrite fails validation for any reason, your original request goes out instead.
|
|
79
|
+
- **Measured.** `lightfoot stats` counts how often the agent goes back for condensed content, and flags rules that cut too much.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Supported agents
|
|
84
|
+
|
|
85
|
+
| Agent | Level | Status |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| Claude Code | 3 · model summaries | Supported |
|
|
88
|
+
| Apps on the Claude Agent SDK | 2 · history edits | Supported |
|
|
89
|
+
| OpenAI Codex CLI | 0 · measure | Experimental |
|
|
90
|
+
| opencode | 0 · measure | Experimental |
|
|
91
|
+
| Gemini CLI | 0 · measure | Experimental, API-key auth only |
|
|
92
|
+
| Cline | wired | Experimental |
|
|
93
|
+
| Roo Code | wired | Experimental (project archived) |
|
|
94
|
+
| Aider | 0 · measure | Measured only |
|
|
95
|
+
| Other tools | wired | Experimental, via `lightfoot run -- <command>` |
|
|
96
|
+
| Cursor, Windsurf | - | Not possible: requests leave from their servers |
|
|
97
|
+
|
|
98
|
+
The level says how much is proven for each agent, from least to most: `wired` (built from its source, unit-tested) > `0 · measure` (its real traffic parsed) > `1 · output rules` > `2 · history edits` > `3 · model summaries` > `certified` (a passing paired eval). Experimental agents stay in shadow mode unless started with `--live --experimental`. [Details per agent](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md#supported-agents).
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Common commands
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
lightfoot claude # start an agent through Lightfoot (also: codex, opencode, gemini, aider)
|
|
106
|
+
lightfoot run -- <command> # any other tool that reads a base-URL variable
|
|
107
|
+
lightfoot estimate # what it would have saved on your past sessions
|
|
108
|
+
lightfoot stats # cost, savings and rule health per session
|
|
109
|
+
lightfoot why # what was condensed in a session, and where the full text is
|
|
110
|
+
lightfoot dashboard # a local report page
|
|
111
|
+
lightfoot shadow off # start saving (shadow on goes back to measuring)
|
|
112
|
+
lightfoot off # kill switch, immediate (lightfoot on resumes)
|
|
113
|
+
lightfoot doctor # check the setup
|
|
114
|
+
lightfoot plugins install --agent gemini # Lightfoot's extension for Gemini CLI (or --agent codex)
|
|
115
|
+
lightfoot skills install # the same guidance as skills, e.g. for opencode
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Resume sessions through Lightfoot too (`lightfoot claude --resume`); resuming without it re-sends the history uncondensed and rewrites the cache once. Hook mode (no proxy, for Claude Code and opencode), the Claude Code plugin and status line, every setting, and troubleshooting: **[the user guide](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md)**.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Privacy
|
|
123
|
+
|
|
124
|
+
- **Local only.** Listens on 127.0.0.1. Requests with other Host headers, and requests from browsers, are refused.
|
|
125
|
+
- **Your credentials** are forwarded unchanged and never written anywhere. With a subscription login, Lightfoot sends no requests of its own.
|
|
126
|
+
- **Project files can't take over.** A repository's `.lightfoot/config.toml` can't redirect your requests or run commands.
|
|
127
|
+
- **Retention.** Stored content is deleted 30 days after a session's last use. The cost ledger holds only token counts.
|
|
128
|
+
- **No telemetry**, no usage tracking, no analytics.
|
|
129
|
+
|
|
130
|
+
It uses about 50 MB of memory and almost no CPU when idle; a turn of a long session costs it a few tens of milliseconds. Works with API keys and with Pro and Max subscriptions ([what that means](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md#pro-and-max-subscriptions)).
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Works well with Graphify and Obsidian
|
|
135
|
+
|
|
136
|
+
Both are optional, detected when present, and never installed unless you ask.
|
|
137
|
+
|
|
138
|
+
- **[Graphify](https://github.com/Graphify-Labs/graphify)** cuts the tokens spent *finding* code. Lightfoot points trimmed searches at `graphify-out/GRAPH_REPORT.md` and drops repeated graph queries.
|
|
139
|
+
- **[Obsidian](https://obsidian.md)** cuts the tokens spent *re-establishing* context. Lightfoot writes a handoff note (what's done, decisions, open threads) into your vault when a session ends.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Learn more
|
|
144
|
+
|
|
145
|
+
- [User guide](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/guide.md): every command and setting, agents, subscriptions, troubleshooting, uninstall
|
|
146
|
+
- [Architecture](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/architecture.md): exactly what Lightfoot does to a request, and why
|
|
147
|
+
- [Comparison](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/comparison.md): how it differs from other token-saving tools
|
|
148
|
+
- [Development](https://github.com/miska-voutilainen/lightfoot/blob/main/docs/development.md): set up, test, measure, release
|
|
149
|
+
- [Security](https://github.com/miska-voutilainen/lightfoot/blob/main/SECURITY.md): guarantees, and how to report a problem
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Contributing
|
|
154
|
+
|
|
155
|
+
Contributions are welcome. See **[CONTRIBUTING.md](https://github.com/miska-voutilainen/lightfoot/blob/main/CONTRIBUTING.md)** for the setup and the git workflow.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
[MIT](https://github.com/miska-voutilainen/lightfoot/blob/main/LICENSE). Lightfoot is an independent project, not affiliated with or endorsed by Anthropic, OpenAI, Google, Graphify or Obsidian.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Protocol adapters, chosen by request path."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from .anthropic import AnthropicAdapter
|
|
8
|
+
from .base import Adapter, Index, Result, ToolCall, apply_changes, count_cache_markers
|
|
9
|
+
from .chat import ChatAdapter
|
|
10
|
+
from .gemini import GeminiAdapter
|
|
11
|
+
from .responses import ResponsesAdapter
|
|
12
|
+
|
|
13
|
+
ANTHROPIC = AnthropicAdapter()
|
|
14
|
+
RESPONSES = ResponsesAdapter()
|
|
15
|
+
GEMINI = GeminiAdapter()
|
|
16
|
+
CHAT = ChatAdapter()
|
|
17
|
+
|
|
18
|
+
GEMINI_PATH_RE = re.compile(r"(?:^|/)models/[^/]+:(?:stream)?generateContent$", re.I)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def for_path(method: str, path: str) -> Adapter | None:
|
|
22
|
+
"""The adapter that rewrites this request, or None for pure passthrough."""
|
|
23
|
+
if method != "POST":
|
|
24
|
+
return None
|
|
25
|
+
path = path.rstrip("/")
|
|
26
|
+
if path.endswith("v1/messages"):
|
|
27
|
+
return ANTHROPIC
|
|
28
|
+
if path.endswith("/responses") or path == "responses":
|
|
29
|
+
return RESPONSES
|
|
30
|
+
if GEMINI_PATH_RE.search(path):
|
|
31
|
+
return GEMINI
|
|
32
|
+
if path.endswith("chat/completions"):
|
|
33
|
+
return CHAT
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"ANTHROPIC",
|
|
39
|
+
"CHAT",
|
|
40
|
+
"GEMINI",
|
|
41
|
+
"RESPONSES",
|
|
42
|
+
"Adapter",
|
|
43
|
+
"Index",
|
|
44
|
+
"Result",
|
|
45
|
+
"ToolCall",
|
|
46
|
+
"apply_changes",
|
|
47
|
+
"count_cache_markers",
|
|
48
|
+
"for_path",
|
|
49
|
+
]
|