devtime-ei 0.1.0__tar.gz → 0.1.2__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.
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/PKG-INFO +113 -30
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/README.md +108 -28
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/pyproject.toml +15 -3
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/__init__.py +1 -1
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/cli.py +55 -7
- devtime_ei-0.1.2/src/devtime/demo.py +75 -0
- devtime_ei-0.1.2/src/devtime/mcp/server.py +42 -0
- devtime_ei-0.1.2/src/devtime/mcp/transport.py +99 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/.devtimeignore +23 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/README.md +5 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/docs/decisions/0001-use-jwt.md +15 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/package.json +15 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/admin/permissions.ts +9 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/auth/login.ts +21 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/auth/middleware.ts +16 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/auth/tokens.ts +11 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/billing/stripe-webhook.ts +25 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/billing/subscription-service.ts +11 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/export/export-csv.ts +14 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/jobs/email-worker.ts +16 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/src/jobs/queues.ts +6 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/tests/auth-login.test.ts +10 -0
- devtime_ei-0.1.2/src/devtime/resources/demo-saas/tests/stripe-signature.test.ts +8 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime_ei.egg-info/PKG-INFO +113 -30
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime_ei.egg-info/SOURCES.txt +17 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime_ei.egg-info/requires.txt +4 -0
- devtime_ei-0.1.0/src/devtime/mcp/server.py +0 -35
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/LICENSE +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/setup.cfg +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/ai/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/ai/local.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/ai/prompts.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/ai/providers.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/assets/devtimeignore.starter +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/config.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/db/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/db/connection.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/db/migrations.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/db/repository.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/db/schema.sql +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/fixtures/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/fixtures/assertions.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/fixtures/loader.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/fixtures/runner.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/intelligence/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/intelligence/claims.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/intelligence/concepts.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/intelligence/context_pack.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/intelligence/evidence.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/intelligence/lineage.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/intelligence/risk.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/intelligence/scoring.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/mcp/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/mcp/schemas.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/mcp/tools.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/output/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/output/json_export.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/output/markdown.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/output/terminal.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/paths.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/privacy.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/extractors/__init__.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/extractors/base.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/extractors/config_files.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/extractors/docs.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/extractors/nextjs.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/extractors/python.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/extractors/tests.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/extractors/typescript.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/file_walker.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/ignore.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/language.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime/scanner/signals.py +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime_ei.egg-info/dependency_links.txt +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime_ei.egg-info/entry_points.txt +0 -0
- {devtime_ei-0.1.0 → devtime_ei-0.1.2}/src/devtime_ei.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devtime-ei
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Local-first Engineering Intelligence for software repositories
|
|
5
5
|
Author-email: Aviad Shakargi <aviad94@gmail.com>
|
|
6
6
|
Maintainer-email: Aviad Shakargi <aviad94@gmail.com>
|
|
@@ -8,7 +8,7 @@ License: Apache-2.0
|
|
|
8
8
|
Project-URL: Homepage, https://github.com/Shakargy/devtime
|
|
9
9
|
Project-URL: Repository, https://github.com/Shakargy/devtime
|
|
10
10
|
Project-URL: Issues, https://github.com/Shakargy/devtime/issues
|
|
11
|
-
Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.1.
|
|
11
|
+
Project-URL: Release Notes, https://github.com/Shakargy/devtime/releases/tag/v0.1.2
|
|
12
12
|
Project-URL: Demo, https://youtu.be/1Hiu3Y9J_SI
|
|
13
13
|
Keywords: devtools,cli,static-analysis,repository-analysis,engineering-intelligence,local-first
|
|
14
14
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -30,8 +30,11 @@ Requires-Dist: pydantic>=2.7
|
|
|
30
30
|
Requires-Dist: sqlalchemy>=2.0
|
|
31
31
|
Requires-Dist: pyyaml>=6.0
|
|
32
32
|
Requires-Dist: pathspec>=0.12
|
|
33
|
+
Provides-Extra: mcp
|
|
34
|
+
Requires-Dist: mcp>=1.2; extra == "mcp"
|
|
33
35
|
Provides-Extra: dev
|
|
34
36
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
37
|
+
Requires-Dist: mcp>=1.2; extra == "dev"
|
|
35
38
|
Dynamic: license-file
|
|
36
39
|
|
|
37
40
|
# DevTime
|
|
@@ -46,16 +49,32 @@ risky changes.
|
|
|
46
49
|
|
|
47
50
|
> No cloud. No telemetry. No code execution. No AI required.
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+

|
|
50
53
|
|
|
51
|
-
Watch the 2-minute demo: DevTime scans
|
|
52
|
-
|
|
53
|
-
decision improves understanding.
|
|
54
|
+
Prefer video? [Watch the 2-minute demo](https://youtu.be/1Hiu3Y9J_SI): DevTime scans
|
|
55
|
+
a repo locally, explains concepts from evidence, surfaces uncertainty, catches a
|
|
56
|
+
risky diff, and shows how a corroborated decision improves understanding.
|
|
54
57
|
|
|
55
58
|
---
|
|
56
59
|
|
|
57
60
|
## Try DevTime in 60 seconds
|
|
58
61
|
|
|
62
|
+
```bash
|
|
63
|
+
pipx install devtime-ei
|
|
64
|
+
dtc demo init
|
|
65
|
+
cd devtime-demo-saas
|
|
66
|
+
dtc init
|
|
67
|
+
dtc scan
|
|
68
|
+
dtc concepts
|
|
69
|
+
dtc explain "Billing Webhooks"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
73
|
+
CLI command remains `dtc`. `dtc demo init` copies a small static example repo into
|
|
74
|
+
`./devtime-demo-saas` so you can try DevTime without cloning this repository.
|
|
75
|
+
|
|
76
|
+
### From source
|
|
77
|
+
|
|
59
78
|
```bash
|
|
60
79
|
git clone https://github.com/Shakargy/devtime.git
|
|
61
80
|
cd devtime
|
|
@@ -98,27 +117,36 @@ steps) is in **[DEMO_SCRIPT.md](DEMO_SCRIPT.md)**.
|
|
|
98
117
|
|
|
99
118
|
## Why this exists
|
|
100
119
|
|
|
101
|
-
Git
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
120
|
+
Git records what changed, but it does not preserve the reasoning behind those
|
|
121
|
+
changes. When you return to a repository - or review one you did not write - you often
|
|
122
|
+
have to reconstruct why a behavior exists, what evidence supports it, and what is
|
|
123
|
+
still uncertain.
|
|
105
124
|
|
|
106
|
-
DevTime builds evidence-backed repository memory: a local layer that
|
|
107
|
-
|
|
125
|
+
DevTime builds evidence-backed repository memory: a local layer that helps a
|
|
126
|
+
codebase explain itself from code, tests, configs, routes, and recorded decisions.
|
|
127
|
+
It shows what the repository can support with evidence - and, just as importantly,
|
|
128
|
+
what it cannot support yet.
|
|
108
129
|
|
|
109
130
|
## Who it is for
|
|
110
131
|
|
|
111
|
-
DevTime is for
|
|
112
|
-
|
|
113
|
-
|
|
132
|
+
DevTime is for people who need to understand a repository from evidence rather than
|
|
133
|
+
memory.
|
|
134
|
+
|
|
135
|
+
It is especially useful if you:
|
|
136
|
+
|
|
137
|
+
- are onboarding to an unfamiliar codebase and need to understand how a feature is implemented;
|
|
138
|
+
- are reviewing a pull request and want to see what evidence supports a behavior;
|
|
139
|
+
- are returning to a project after weeks or months and cannot remember why something exists;
|
|
140
|
+
- maintain a long-lived project where design decisions are easily lost;
|
|
141
|
+
- want repository understanding to be backed by code and recorded decisions instead of generated summaries.
|
|
114
142
|
|
|
115
|
-
|
|
143
|
+
Questions DevTime helps answer include:
|
|
116
144
|
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
145
|
+
- Where is authentication actually implemented?
|
|
146
|
+
- What files prove that Billing Webhooks exist?
|
|
147
|
+
- What is still uncertain?
|
|
148
|
+
- Did this diff touch a risky concept?
|
|
149
|
+
- Is there a decision explaining this behavior?
|
|
122
150
|
|
|
123
151
|
## What DevTime does
|
|
124
152
|
|
|
@@ -178,14 +206,75 @@ Anything outside these six is out of scope for V0. See [LIMITATIONS.md](LIMITATI
|
|
|
178
206
|
| `dtc decision add` | Add a local decision record that can reduce uncertainty. |
|
|
179
207
|
|
|
180
208
|
(Also available: `dtc evidence`, `dtc debt`, `dtc status`, `dtc doctor --privacy`,
|
|
181
|
-
`dtc export`, `dtc reset`.)
|
|
209
|
+
`dtc export`, `dtc reset`, `dtc mcp start`.)
|
|
182
210
|
|
|
183
211
|
Requires **Python >= 3.11** and git. See **[QUICKSTART.md](QUICKSTART.md)** for a
|
|
184
212
|
step-by-step first run and troubleshooting.
|
|
185
213
|
|
|
214
|
+
## Use with coding agents (MCP)
|
|
215
|
+
|
|
216
|
+
Your coding agent starts every session amnesiac about your repository and then
|
|
217
|
+
guesses, confidently. DevTime gives it memory it can trust: a local, read-only MCP
|
|
218
|
+
server that answers only with claims the repository can prove, plus explicit
|
|
219
|
+
uncertainty for what it cannot.
|
|
220
|
+
|
|
221
|
+
Install with MCP support and scan your repo:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
pipx install "devtime-ei[mcp]"
|
|
225
|
+
cd your-repo
|
|
226
|
+
dtc init
|
|
227
|
+
dtc scan
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Add DevTime to Claude Code:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
claude mcp add devtime -- dtc mcp start
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Or in any MCP client that reads `.mcp.json`:
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"mcpServers": {
|
|
241
|
+
"devtime": {
|
|
242
|
+
"command": "dtc",
|
|
243
|
+
"args": ["mcp", "start"]
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The agent gets three read-only tools: `list_concepts`, `explain_concept`, and
|
|
250
|
+
`get_context_pack` (governed context with do-not-change-without-review paths, tests
|
|
251
|
+
to run, and agent guidance). Local stdio only - no network listener, no write tools,
|
|
252
|
+
no source code returned, only evidence file paths.
|
|
253
|
+
|
|
254
|
+
DevTime is listed in the official MCP Registry as `io.github.shakargy/devtime`.
|
|
255
|
+
|
|
256
|
+
<!-- mcp-name: io.github.shakargy/devtime -->
|
|
257
|
+
|
|
186
258
|
## Installation
|
|
187
259
|
|
|
188
|
-
Recommended
|
|
260
|
+
Recommended: install from PyPI with [pipx](https://pipx.pypa.io/) so the `dtc`
|
|
261
|
+
command is available on your PATH in an isolated environment:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
pipx install devtime-ei
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Or with pip:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
pip install devtime-ei
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
274
|
+
CLI command remains `dtc`. After installing, run `dtc demo init` to create a local
|
|
275
|
+
example repo to try it on.
|
|
276
|
+
|
|
277
|
+
### From source
|
|
189
278
|
|
|
190
279
|
```bash
|
|
191
280
|
git clone https://github.com/Shakargy/devtime.git
|
|
@@ -205,12 +294,6 @@ python -m venv .venv
|
|
|
205
294
|
pip install -e ".[dev]"
|
|
206
295
|
```
|
|
207
296
|
|
|
208
|
-
Planned PyPI install (after the package is published and verified):
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
pipx install devtime
|
|
212
|
-
```
|
|
213
|
-
|
|
214
297
|
## Example output
|
|
215
298
|
|
|
216
299
|
```
|
|
@@ -274,7 +357,7 @@ intentionally not built yet - in **[LIMITATIONS.md](LIMITATIONS.md)**.
|
|
|
274
357
|
## Roadmap
|
|
275
358
|
|
|
276
359
|
This is an early, local-first V0 focused on being trustworthy before being large.
|
|
277
|
-
Not yet built (intentionally): git-history signals,
|
|
360
|
+
Not yet built (intentionally): git-history signals, write-enabled MCP tools, an AI
|
|
278
361
|
provider, a UI, and any cloud/team/enterprise features. See **[ROADMAP.md](ROADMAP.md)**.
|
|
279
362
|
|
|
280
363
|
## Contributing
|
|
@@ -10,16 +10,32 @@ risky changes.
|
|
|
10
10
|
|
|
11
11
|
> No cloud. No telemetry. No code execution. No AI required.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+

|
|
14
14
|
|
|
15
|
-
Watch the 2-minute demo: DevTime scans
|
|
16
|
-
|
|
17
|
-
decision improves understanding.
|
|
15
|
+
Prefer video? [Watch the 2-minute demo](https://youtu.be/1Hiu3Y9J_SI): DevTime scans
|
|
16
|
+
a repo locally, explains concepts from evidence, surfaces uncertainty, catches a
|
|
17
|
+
risky diff, and shows how a corroborated decision improves understanding.
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
## Try DevTime in 60 seconds
|
|
22
22
|
|
|
23
|
+
```bash
|
|
24
|
+
pipx install devtime-ei
|
|
25
|
+
dtc demo init
|
|
26
|
+
cd devtime-demo-saas
|
|
27
|
+
dtc init
|
|
28
|
+
dtc scan
|
|
29
|
+
dtc concepts
|
|
30
|
+
dtc explain "Billing Webhooks"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
34
|
+
CLI command remains `dtc`. `dtc demo init` copies a small static example repo into
|
|
35
|
+
`./devtime-demo-saas` so you can try DevTime without cloning this repository.
|
|
36
|
+
|
|
37
|
+
### From source
|
|
38
|
+
|
|
23
39
|
```bash
|
|
24
40
|
git clone https://github.com/Shakargy/devtime.git
|
|
25
41
|
cd devtime
|
|
@@ -62,27 +78,36 @@ steps) is in **[DEMO_SCRIPT.md](DEMO_SCRIPT.md)**.
|
|
|
62
78
|
|
|
63
79
|
## Why this exists
|
|
64
80
|
|
|
65
|
-
Git
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
81
|
+
Git records what changed, but it does not preserve the reasoning behind those
|
|
82
|
+
changes. When you return to a repository - or review one you did not write - you often
|
|
83
|
+
have to reconstruct why a behavior exists, what evidence supports it, and what is
|
|
84
|
+
still uncertain.
|
|
69
85
|
|
|
70
|
-
DevTime builds evidence-backed repository memory: a local layer that
|
|
71
|
-
|
|
86
|
+
DevTime builds evidence-backed repository memory: a local layer that helps a
|
|
87
|
+
codebase explain itself from code, tests, configs, routes, and recorded decisions.
|
|
88
|
+
It shows what the repository can support with evidence - and, just as importantly,
|
|
89
|
+
what it cannot support yet.
|
|
72
90
|
|
|
73
91
|
## Who it is for
|
|
74
92
|
|
|
75
|
-
DevTime is for
|
|
76
|
-
|
|
77
|
-
|
|
93
|
+
DevTime is for people who need to understand a repository from evidence rather than
|
|
94
|
+
memory.
|
|
95
|
+
|
|
96
|
+
It is especially useful if you:
|
|
97
|
+
|
|
98
|
+
- are onboarding to an unfamiliar codebase and need to understand how a feature is implemented;
|
|
99
|
+
- are reviewing a pull request and want to see what evidence supports a behavior;
|
|
100
|
+
- are returning to a project after weeks or months and cannot remember why something exists;
|
|
101
|
+
- maintain a long-lived project where design decisions are easily lost;
|
|
102
|
+
- want repository understanding to be backed by code and recorded decisions instead of generated summaries.
|
|
78
103
|
|
|
79
|
-
|
|
104
|
+
Questions DevTime helps answer include:
|
|
80
105
|
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
106
|
+
- Where is authentication actually implemented?
|
|
107
|
+
- What files prove that Billing Webhooks exist?
|
|
108
|
+
- What is still uncertain?
|
|
109
|
+
- Did this diff touch a risky concept?
|
|
110
|
+
- Is there a decision explaining this behavior?
|
|
86
111
|
|
|
87
112
|
## What DevTime does
|
|
88
113
|
|
|
@@ -142,14 +167,75 @@ Anything outside these six is out of scope for V0. See [LIMITATIONS.md](LIMITATI
|
|
|
142
167
|
| `dtc decision add` | Add a local decision record that can reduce uncertainty. |
|
|
143
168
|
|
|
144
169
|
(Also available: `dtc evidence`, `dtc debt`, `dtc status`, `dtc doctor --privacy`,
|
|
145
|
-
`dtc export`, `dtc reset`.)
|
|
170
|
+
`dtc export`, `dtc reset`, `dtc mcp start`.)
|
|
146
171
|
|
|
147
172
|
Requires **Python >= 3.11** and git. See **[QUICKSTART.md](QUICKSTART.md)** for a
|
|
148
173
|
step-by-step first run and troubleshooting.
|
|
149
174
|
|
|
175
|
+
## Use with coding agents (MCP)
|
|
176
|
+
|
|
177
|
+
Your coding agent starts every session amnesiac about your repository and then
|
|
178
|
+
guesses, confidently. DevTime gives it memory it can trust: a local, read-only MCP
|
|
179
|
+
server that answers only with claims the repository can prove, plus explicit
|
|
180
|
+
uncertainty for what it cannot.
|
|
181
|
+
|
|
182
|
+
Install with MCP support and scan your repo:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
pipx install "devtime-ei[mcp]"
|
|
186
|
+
cd your-repo
|
|
187
|
+
dtc init
|
|
188
|
+
dtc scan
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Add DevTime to Claude Code:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
claude mcp add devtime -- dtc mcp start
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Or in any MCP client that reads `.mcp.json`:
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"mcpServers": {
|
|
202
|
+
"devtime": {
|
|
203
|
+
"command": "dtc",
|
|
204
|
+
"args": ["mcp", "start"]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The agent gets three read-only tools: `list_concepts`, `explain_concept`, and
|
|
211
|
+
`get_context_pack` (governed context with do-not-change-without-review paths, tests
|
|
212
|
+
to run, and agent guidance). Local stdio only - no network listener, no write tools,
|
|
213
|
+
no source code returned, only evidence file paths.
|
|
214
|
+
|
|
215
|
+
DevTime is listed in the official MCP Registry as `io.github.shakargy/devtime`.
|
|
216
|
+
|
|
217
|
+
<!-- mcp-name: io.github.shakargy/devtime -->
|
|
218
|
+
|
|
150
219
|
## Installation
|
|
151
220
|
|
|
152
|
-
Recommended
|
|
221
|
+
Recommended: install from PyPI with [pipx](https://pipx.pypa.io/) so the `dtc`
|
|
222
|
+
command is available on your PATH in an isolated environment:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
pipx install devtime-ei
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Or with pip:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
pip install devtime-ei
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The PyPI distribution is `devtime-ei`. The Python package remains `devtime`, and the
|
|
235
|
+
CLI command remains `dtc`. After installing, run `dtc demo init` to create a local
|
|
236
|
+
example repo to try it on.
|
|
237
|
+
|
|
238
|
+
### From source
|
|
153
239
|
|
|
154
240
|
```bash
|
|
155
241
|
git clone https://github.com/Shakargy/devtime.git
|
|
@@ -169,12 +255,6 @@ python -m venv .venv
|
|
|
169
255
|
pip install -e ".[dev]"
|
|
170
256
|
```
|
|
171
257
|
|
|
172
|
-
Planned PyPI install (after the package is published and verified):
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
pipx install devtime
|
|
176
|
-
```
|
|
177
|
-
|
|
178
258
|
## Example output
|
|
179
259
|
|
|
180
260
|
```
|
|
@@ -238,7 +318,7 @@ intentionally not built yet - in **[LIMITATIONS.md](LIMITATIONS.md)**.
|
|
|
238
318
|
## Roadmap
|
|
239
319
|
|
|
240
320
|
This is an early, local-first V0 focused on being trustworthy before being large.
|
|
241
|
-
Not yet built (intentionally): git-history signals,
|
|
321
|
+
Not yet built (intentionally): git-history signals, write-enabled MCP tools, an AI
|
|
242
322
|
provider, a UI, and any cloud/team/enterprise features. See **[ROADMAP.md](ROADMAP.md)**.
|
|
243
323
|
|
|
244
324
|
## Contributing
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "devtime-ei"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
description = "Local-first Engineering Intelligence for software repositories"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -37,15 +37,20 @@ dependencies = [
|
|
|
37
37
|
]
|
|
38
38
|
|
|
39
39
|
[project.optional-dependencies]
|
|
40
|
+
# Read-only MCP stdio server for coding agents (dtc mcp start).
|
|
41
|
+
mcp = [
|
|
42
|
+
"mcp>=1.2",
|
|
43
|
+
]
|
|
40
44
|
dev = [
|
|
41
45
|
"pytest>=8.0",
|
|
46
|
+
"mcp>=1.2",
|
|
42
47
|
]
|
|
43
48
|
|
|
44
49
|
[project.urls]
|
|
45
50
|
Homepage = "https://github.com/Shakargy/devtime"
|
|
46
51
|
Repository = "https://github.com/Shakargy/devtime"
|
|
47
52
|
Issues = "https://github.com/Shakargy/devtime/issues"
|
|
48
|
-
"Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.1.
|
|
53
|
+
"Release Notes" = "https://github.com/Shakargy/devtime/releases/tag/v0.1.2"
|
|
49
54
|
Demo = "https://youtu.be/1Hiu3Y9J_SI"
|
|
50
55
|
|
|
51
56
|
[project.scripts]
|
|
@@ -59,8 +64,15 @@ build-backend = "setuptools.build_meta"
|
|
|
59
64
|
where = ["src"]
|
|
60
65
|
|
|
61
66
|
# Non-Python runtime files that ship inside the package (read at runtime).
|
|
67
|
+
# The demo-saas resource is copied out by `dtc demo init`; the leading-dot
|
|
68
|
+
# .devtimeignore is listed explicitly because glob `*` does not match dotfiles.
|
|
62
69
|
[tool.setuptools.package-data]
|
|
63
|
-
devtime = [
|
|
70
|
+
devtime = [
|
|
71
|
+
"db/*.sql",
|
|
72
|
+
"assets/*",
|
|
73
|
+
"resources/demo-saas/**/*",
|
|
74
|
+
"resources/demo-saas/.devtimeignore",
|
|
75
|
+
]
|
|
64
76
|
|
|
65
77
|
[tool.pytest.ini_options]
|
|
66
78
|
testpaths = ["tests"]
|
|
@@ -24,9 +24,13 @@ console = Console()
|
|
|
24
24
|
claim_app = typer.Typer(help="Inspect and govern claims.")
|
|
25
25
|
decision_app = typer.Typer(help="Record human decisions.")
|
|
26
26
|
mcp_app = typer.Typer(help="Local read-only MCP server.")
|
|
27
|
+
demo_app = typer.Typer(
|
|
28
|
+
help="Create a local copy of the bundled demo repository.", no_args_is_help=True
|
|
29
|
+
)
|
|
27
30
|
app.add_typer(claim_app, name="claim")
|
|
28
31
|
app.add_typer(decision_app, name="decision")
|
|
29
32
|
app.add_typer(mcp_app, name="mcp")
|
|
33
|
+
app.add_typer(demo_app, name="demo")
|
|
30
34
|
|
|
31
35
|
|
|
32
36
|
# --------------------------------------------------------------------------- #
|
|
@@ -43,6 +47,37 @@ def init() -> None:
|
|
|
43
47
|
console.print("AI disabled. Cloud disabled. Telemetry off. MCP read-only.")
|
|
44
48
|
|
|
45
49
|
|
|
50
|
+
@demo_app.command("init")
|
|
51
|
+
def demo_init(
|
|
52
|
+
force: bool = typer.Option(
|
|
53
|
+
False, "--force", help="Replace devtime-demo-saas if it already exists."
|
|
54
|
+
),
|
|
55
|
+
) -> None:
|
|
56
|
+
"""Copy the bundled demo repository into ./devtime-demo-saas (static files only)."""
|
|
57
|
+
from devtime.demo import DEMO_DIR_NAME, DemoExistsError, create_demo
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
create_demo(Path.cwd(), force=force)
|
|
61
|
+
except DemoExistsError as exc:
|
|
62
|
+
console.print(
|
|
63
|
+
f"[yellow]{DEMO_DIR_NAME}/ already exists[/yellow] at {exc.path}."
|
|
64
|
+
)
|
|
65
|
+
console.print(
|
|
66
|
+
"Use [bold]dtc demo init --force[/bold] to replace it, "
|
|
67
|
+
"or remove the directory first."
|
|
68
|
+
)
|
|
69
|
+
raise typer.Exit(code=1)
|
|
70
|
+
|
|
71
|
+
console.print(f"[green]Demo repository created[/green] at ./{DEMO_DIR_NAME}")
|
|
72
|
+
console.print("")
|
|
73
|
+
console.print("Next:")
|
|
74
|
+
console.print(f" cd {DEMO_DIR_NAME}")
|
|
75
|
+
console.print(" dtc init")
|
|
76
|
+
console.print(" dtc scan")
|
|
77
|
+
console.print(" dtc concepts")
|
|
78
|
+
console.print(' dtc explain "Billing Webhooks"')
|
|
79
|
+
|
|
80
|
+
|
|
46
81
|
@app.command()
|
|
47
82
|
def status() -> None:
|
|
48
83
|
"""Show local storage, AI, cloud, telemetry, MCP, and scan status."""
|
|
@@ -306,20 +341,33 @@ def decision_add(
|
|
|
306
341
|
|
|
307
342
|
@mcp_app.command("start")
|
|
308
343
|
def mcp_start() -> None:
|
|
309
|
-
"""
|
|
310
|
-
|
|
344
|
+
"""Start the local read-only MCP server over stdio (for coding agents)."""
|
|
345
|
+
# stdout belongs to the JSON-RPC stream: all diagnostics go to stderr.
|
|
346
|
+
err = Console(stderr=True)
|
|
347
|
+
|
|
348
|
+
if not paths.is_initialized():
|
|
349
|
+
err.print("[red]DevTime is not initialized here.[/red]")
|
|
350
|
+
err.print("Run [bold]dtc init[/bold] and [bold]dtc scan[/bold] in the repository first.")
|
|
351
|
+
raise typer.Exit(code=2)
|
|
352
|
+
|
|
353
|
+
from devtime.mcp.transport import McpDependencyMissing, run_stdio
|
|
311
354
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
355
|
+
err.print("DevTime MCP server: stdio, read-only, local only. Ctrl+C to stop.")
|
|
356
|
+
try:
|
|
357
|
+
run_stdio()
|
|
358
|
+
except McpDependencyMissing as exc:
|
|
359
|
+
# markup=False: the hint contains [mcp], which rich would eat as a tag.
|
|
360
|
+
err.print(str(exc), markup=False, style="red")
|
|
361
|
+
raise typer.Exit(code=1)
|
|
315
362
|
|
|
316
363
|
|
|
317
364
|
@mcp_app.command("preview")
|
|
318
365
|
def mcp_preview() -> None:
|
|
319
|
-
"""
|
|
366
|
+
"""Show implemented and planned read-only MCP tools."""
|
|
320
367
|
from devtime.mcp.server import describe_server
|
|
321
368
|
|
|
322
|
-
|
|
369
|
+
# markup=False: the text contains [mcp], which rich would eat as a tag.
|
|
370
|
+
console.print(describe_server(), markup=False)
|
|
323
371
|
|
|
324
372
|
|
|
325
373
|
@mcp_app.command("status")
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Bundled demo repository support for `dtc demo init`.
|
|
2
|
+
|
|
3
|
+
This lets people who installed DevTime from PyPI (`pipx install devtime-ei`) try it
|
|
4
|
+
without cloning the source repository. It copies a small, static example repo that
|
|
5
|
+
ships inside the installed package into the current working directory.
|
|
6
|
+
|
|
7
|
+
It only copies static files. It never executes code, never installs anything, never
|
|
8
|
+
runs tests or migrations, and never touches the network. Nothing leaves the machine.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import shutil
|
|
14
|
+
from importlib import resources
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
# Directory name created in the current working directory.
|
|
18
|
+
DEMO_DIR_NAME = "devtime-demo-saas"
|
|
19
|
+
|
|
20
|
+
# The packaged demo lives at src/devtime/resources/demo-saas/ and ships in the wheel
|
|
21
|
+
# via [tool.setuptools.package-data].
|
|
22
|
+
_RESOURCE_SUBPATH = ("resources", "demo-saas")
|
|
23
|
+
|
|
24
|
+
# Artifacts that must never end up in a copied demo, stripped defensively after copy.
|
|
25
|
+
_FORBIDDEN_DIRS = {".devtime", ".git", "node_modules", "__pycache__", ".cache"}
|
|
26
|
+
_FORBIDDEN_FILE_SUFFIXES = (".sqlite", ".sqlite3", ".db")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DemoExistsError(Exception):
|
|
30
|
+
"""Raised when the demo directory already exists and force was not requested."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, path: Path) -> None:
|
|
33
|
+
self.path = path
|
|
34
|
+
super().__init__(str(path))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def packaged_demo_source() -> Path:
|
|
38
|
+
"""Return a filesystem path to the demo directory bundled in the package."""
|
|
39
|
+
root = resources.files("devtime")
|
|
40
|
+
source = root.joinpath(*_RESOURCE_SUBPATH)
|
|
41
|
+
# In a normal wheel/editable install this is already a real path on disk.
|
|
42
|
+
return Path(str(source))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _strip_forbidden(dest: Path) -> None:
|
|
46
|
+
"""Remove any artifacts that must never be part of a shared demo."""
|
|
47
|
+
for path in sorted(dest.rglob("*"), reverse=True):
|
|
48
|
+
if path.is_dir() and path.name in _FORBIDDEN_DIRS:
|
|
49
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
50
|
+
elif path.is_file() and path.suffix.lower() in _FORBIDDEN_FILE_SUFFIXES:
|
|
51
|
+
path.unlink(missing_ok=True)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def create_demo(dest_parent: Path, *, force: bool = False) -> Path:
|
|
55
|
+
"""Copy the bundled demo into ``dest_parent/devtime-demo-saas``.
|
|
56
|
+
|
|
57
|
+
Writes only inside ``dest_parent``. Returns the created directory path.
|
|
58
|
+
Raises :class:`DemoExistsError` if the destination exists and ``force`` is False.
|
|
59
|
+
"""
|
|
60
|
+
dest = dest_parent / DEMO_DIR_NAME
|
|
61
|
+
if dest.exists():
|
|
62
|
+
if not force:
|
|
63
|
+
raise DemoExistsError(dest)
|
|
64
|
+
shutil.rmtree(dest)
|
|
65
|
+
|
|
66
|
+
source = packaged_demo_source()
|
|
67
|
+
if not source.is_dir():
|
|
68
|
+
raise FileNotFoundError(f"Bundled demo not found at {source}")
|
|
69
|
+
|
|
70
|
+
# as_file guarantees a real filesystem path even if the package were zipped.
|
|
71
|
+
with resources.as_file(resources.files("devtime").joinpath(*_RESOURCE_SUBPATH)) as src_path:
|
|
72
|
+
shutil.copytree(src_path, dest)
|
|
73
|
+
|
|
74
|
+
_strip_forbidden(dest)
|
|
75
|
+
return dest
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""MCP server description (Builder Edition, Chapter 16).
|
|
2
|
+
|
|
3
|
+
v0.1.2: the stdio transport is implemented for the read-only tool subset in
|
|
4
|
+
devtime.mcp.transport. The remaining planned tools stay listed as planned so
|
|
5
|
+
the preview output never overclaims.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
from devtime.mcp import schemas
|
|
13
|
+
from devtime.mcp.transport import IMPLEMENTED_TOOLS
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def describe_server() -> str:
|
|
17
|
+
"""Honest preview: implemented tools are separated from planned ones."""
|
|
18
|
+
planned_read = [t for t in schemas.TOOLS["read"] if t not in IMPLEMENTED_TOOLS]
|
|
19
|
+
planned_context = [t for t in schemas.TOOLS["context"] if t not in IMPLEMENTED_TOOLS]
|
|
20
|
+
lines = [
|
|
21
|
+
"MCP transport: stdio, read-only, local only.",
|
|
22
|
+
'Requires the optional dependency: pip install "devtime-ei[mcp]"',
|
|
23
|
+
"Start with: dtc mcp start (stdout is the protocol stream).",
|
|
24
|
+
"",
|
|
25
|
+
"Implemented tools:",
|
|
26
|
+
]
|
|
27
|
+
lines += [f" - {t}" for t in IMPLEMENTED_TOOLS]
|
|
28
|
+
lines += ["Planned read tools (not implemented yet):"]
|
|
29
|
+
lines += [f" - {t}" for t in planned_read]
|
|
30
|
+
lines += ["Planned context tools (not implemented yet):"]
|
|
31
|
+
lines += [f" - {t}" for t in planned_context]
|
|
32
|
+
lines += ["Planned review tools (not implemented yet):"]
|
|
33
|
+
lines += [f" - {t}" for t in schemas.TOOLS["review"]]
|
|
34
|
+
lines += [
|
|
35
|
+
"",
|
|
36
|
+
"Write tools are not exposed. No network listener. No source code is returned.",
|
|
37
|
+
]
|
|
38
|
+
return "\n".join(lines)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def describe_permissions() -> str:
|
|
42
|
+
return json.dumps(schemas.DEFAULT_PERMISSIONS, indent=2)
|