- 🤖 LLM usage: $3.8584 (110 commits)
- 👤 Human dev: ~$3603 (36.0h @ $100/h, 30min dedup)
Generated on 2026-08-01 using openrouter/qwen/qwen3-coder-next
todo2code buduje wspólny Intent Evidence DSL z poleceń, historii Git, aktualnego kodu, list zadań, changelogu i dokumentacji. Następnie łączy rekordy w graf przepływu wiedzy, wykrywa rozbieżności i generuje raport dla zespołu.
Projekt działa na Node.js/TypeScript. Wielojęzykowe fakty kodu dostarczają
adaptery TypeScript/JavaScript, Python (ast), Go (go/ast), Java (JDK
Compiler Tree API), Rust (syn) i PHP (token_get_all z TOKEN_PARSE). Toolchainy poza Node są opcjonalne — brak
narzędzia daje jawne ostrzeżenie tylko wtedy, gdy repo zawiera pasujące źródła.
Integracje są dostępne przez CLI, MCP/stdio i A2A v1.0/JSON-RPC.
Repozytorium stosuje wellmanifest/new-project 0.8.0. Każda wieloetapowa
zmiana wymaga aktywnego project/ticket-{NNN}, planu przedstawionego przed
implementacją oraz intent v2 ograniczającego workstream, dozwolone ścieżki,
zależności, konflikty i integrację. Kilka ticketów może być aktywnych wyłącznie
w różnych workstreamach i bez nakładania zakresu zapisu; jeden branch/PR musi
rozwiązać się do dokładnie jednego ticketu. make governance emituje stabilne
kody GOV-* i sprawdza integralność przypiętych plików, własność user-*.md,
graf zależności, zakres, Docker oraz profile Node/Docker. W Pull Request CI
wymaga niezależnego GitHub Review; wpis agenta w Markdown nie jest zaufanym
zatwierdzeniem merge. Trwałe instrukcje zawiera AGENTS.md.
Wersja 0.5.0 ma działającą ścieżkę źródła → kanoniczny DSL → graf →
diagnostyka/Intent vs Reality → raport oraz zamknięty, reviewowalny przepływ
DSL2TODO. Kontrakty t2c.conclusion/v1, t2c.todo-proposal/v1,
t2c.todo-patch/v1, t2c.code-change-plan/v1,
t2c.code-change-acceptance/v1 i t2c.code-change-close-result/v1 mają jawne
kontrakty oraz proweniencję. CLI, MCP, A2A i pięć SDK
potrafią syntetyzować zadania, klasyfikować duplikaty, renderować audytowany
TODO.patch i zastosować go wyłącznie po jawnej akceptacji jego hasha. Główny
pipeline może zapisać artefakty review przez --task-mode, lecz nigdy sam nie
modyfikuje TODO.md.
Otwarte diagnostyki implementacyjne można przekształcić w ugruntowany plan
zmiany kodu, hash-bound review i strukturalną propozycję source patch, a po
implementacji ocenić przez ponowną analizę grafu. Pipeline nigdy nie stosuje
patcha automatycznie; osobne apply-source-patch wymaga kompletnego diffu,
tożsamości zatwierdzającego i dokładnego patchHash. Diagram i polecenia zawiera
docs/CODE_CHANGE_PLANS.md.
Aktualna macierz komponentów, wyniki walidacji, znane ograniczenia i projekt
docelowego DSL2TODO znajdują się w
docs/PROJECT_STATUS.md. Priorytety implementacyjne
są utrzymywane w TODO.md.
Czy projekt jest kompletny? Nie — warstwa deterministyczna jest operacyjnie
dojrzała, natomiast semantyczna mierzy niskie pokrycie na obcych repozytoriach.
Ocenę dystansu do wydania, kryteria zamknięcia i listę blokerów z pomiarami zawiera
docs/READINESS.md.
Komunikację zespołu można zapisywać append-only w project/<ticket>/. Główny
pipeline domyślnie zachowuje uczestnika i rolę human|agent, porównuje
wypowiedzi z dowodami Git/AST, zapisuje analizę w manifeście i dodaje problemy
do diagnostyki. Claim agenta pozostaje claimem, nigdy faktem wykonania.
Kontrakt plików i gotowe polecenia opisuje
docs/TEAM_COMMUNICATION.md.
Opcjonalny project/participants.json wiąże kanoniczne human:<id> i
agent:<id> z autorami Git, identyfikatorami A2A oraz aliasami ludzi bez
zgadywania tożsamości na podstawie nazw wyświetlanych.
Praktyczny przebieg CLI — od instalacji przez tryb offline/LLM po diff,
Intent vs Reality, komunikację i automatyczną kontrolę wszystkich przykładów —
opisuje docs/CLI_GUIDE.md.
| Etap | Mechanizm | LLM |
|---|---|---|
| NL → DSL | OpenRouter structured output; jawny fallback heurystyczny/TensorFlow | tak, domyślnie wymagany |
| 10 commitów Git → DSL | git log, diff, heurystyki symboli |
nie |
| TypeScript/JavaScript/Python/Go/Java/Rust/PHP → DSL | natywne parsery języków; Java Tree API, Rust syn, PHP syntax tokens |
nie |
| TODO + CHANGELOG → DSL | deterministyczna struktura + audytowane wzbogacanie OpenRouter | tak, domyślnie wymagany |
| Dokumentacja → DSL | deterministyczny baseline + opcjonalne OpenRouter structured outputs | opcjonalnie |
| JSON/YAML/TOML, Docker i CI → DSL | deterministyczny konwerter struktury konfiguracji | nie |
project/<ticket>/ komunikacja → DSL + synteza per uczestnik |
deterministyczny kontrakt; audytowane wzbogacanie OpenRouter | tak, domyślnie wymagany |
| Linkowanie i diagnostyka | deterministyczny graf relacji | nie |
| Graf + diagnostyka → propozycje TODO | OpenRouter structured output; jawny pusty fallback bez pozornej syntezy | tak |
| Propozycje → patch → approved apply | deterministyczna walidacja, renderer i atomowy zapis | nie |
| Diagnostyka → code-change plan → acceptance/close | deterministyczny plan dla konkretnych plików (bez vendoringu, binariów i artefaktów runu) oraz bramka plan-set po re-analizie; bez auto-apply i auto-DONE | nie |
Graf DSL → t2c.conclusion/v1 → raport NL |
OpenRouter structured output; runtime waliduje cytowania przed deterministycznym renderingiem Markdown | tak |
Moduły deterministyczne nie importują klienta OpenRouter. Sprawdzają to
npm run verify:no-llm oraz bezcykliczny graf modułów npm run verify:modules.
Kompletność i brak duplikatów zmiennych sprawdza npm run verify:env.
Osobny wymagany job CI instaluje Temurin JDK 17 i uruchamia fixture adaptera
Java z T2C_REQUIRE_JAVA_TEST=1, co zamienia brak runtime w błąd zamiast skipu.
Wersjonowany benchmark semantyczny uruchamia npm run evaluate:gold
(t2c.gold-dataset/v2; poprzednia próba pozostaje pod evaluate:gold:v1).
Mierzy on precision/recall ekstrakcji w czterech kanałach, linkowania osobno dla
exact-target i capability-topic, kodów diagnostycznych (w tym fałszywego
DONE), kompletność cytowań DSL2TODO, deduplikację oraz stabilność dwóch
identycznych przebiegów offline. Luki udokumentowane jako knownGap — dziś
polska proza wobec angielskiego modułu — są raportowane osobno i nie wchodzą do
precision/recall.
Cele symboliczne NL są rozstrzygane względem zaobserwowanych deklaracji AST.
Krótki symbol tworzy dowód tylko wtedy, gdy ma jednego właściciela; przy wielu
modułach linker abstenuje, a AMBIGUOUS_REQUIREMENT podaje kandydatów i prosi
o target.path. Jawna ścieżka lub kwalifikowana nazwa może wybrać jeden moduł.
Sama ścieżka pozostaje relacją nawigacyjną, lecz nie zamyka deklaracji nowej
funkcji: wymagany jest symbol, temat obecny w wyekstrahowanych możliwościach,
uziemiona zgodność z konkretnym faktem/commitem albo zaakceptowany rerank.
Rzeczywiste kontrakty NL → DSL oraz graf → wnioski można sprawdzić osobno przez
npm run live:check. Kontrola jest opt-in, używa require-llm, zapisuje tylko
zredagowany audyt latencji/tokenów/kosztu i bez klucza kończy się jako SKIPPED;
wymagane testy offline nigdy nie zależą od dostępności providera.
Wymagania: Node.js 20+ i Git. Opcjonalne adaptery wymagają odpowiednio Python 3.10+, Go, JDK 17+, Cargo/Rust lub PHP 8+.
cp .env.example .env
npm install
npm run build
node dist/src/cli.js doctorZwykłe npm install i make install instalują wyłącznie rdzeń, dla którego
audyt z 2026-07-29 ma 0 podatności. make install-tf instaluje
@tensorflow/tfjs-node@4.22.0 w odizolowanym adapters/tensorflow/node_modules;
jego 8 zgłoszeń nie trafia do drzewa zależności rdzenia. Nie należy stosować
npm audit fix --force, ponieważ proponuje niekompatybilny downgrade.
Poniższa demonstracja używa wersjonowanego repozytorium examples/, nie wymaga
klucza ani połączenia z OpenRouter i pozostawia jednoznaczny audyt. Uruchom:
make demoPolecenie wykonuje kolejno NL → DSL, Git → DSL, AST → DSL, osobne konwertery
TODO/CHANGELOG, deterministyczne konwertery dokumentacji i konfiguracji,
linker, diagnostykę i deterministyczne podsumowanie. Następnie
analizuje komunikację examples/project/DEMO-101 osobno dla ludzi i agentów.
Wyniki trafiają do examples/.intent-demo/runs/<run-id>/ oraz
examples/.intent-communication/. Stan ostatniego runu można wyświetlić bez
dodatkowych narzędzi:
node --input-type=module <<'NODE'
import { readFile } from 'node:fs/promises';
const latest = JSON.parse(await readFile('examples/.intent-demo/latest.json', 'utf8'));
const manifest = JSON.parse(await readFile(`examples/${latest.runDirectory}/manifest.json`, 'utf8'));
const graph = JSON.parse(await readFile(`examples/${manifest.files.graph}`, 'utf8'));
const stages = Object.fromEntries(Object.entries(manifest.stages).map(([name, stage]) => [name, {
status: stage.status,
effectiveMode: stage.effectiveMode,
reason: stage.reason?.code ?? null,
runtimeVersion: stage.runtimeVersion,
}]));
console.log({ status: manifest.status, runtime: manifest.runtime, stages });
console.log({ records: graph.records.length, relations: graph.relations.length, bySource: graph.stats.bySource });
NODEWeryfikowany wynik dla 0.5.0 ma 227 rekordów, w tym 5 wersjonowanych rekordów
komunikacji. Liczba relacji zależy również od
ostatnich 10 commitów Git, dlatego po każdym commicie może się prawidłowo
zmienić i należy odczytać ją z bieżącego grafu:
status: succeeded, runtime: todo2code 0.5.0
naturalLanguageExtraction: succeeded / deterministic
markdownExtraction: succeeded / deterministic
documentationExtraction: succeeded / deterministic
summary: skipped / deterministic / LLM_DISABLED
records: 227, relations: <zależne od ostatnich 10 commitów>
bySource: agent_log=5, ast=190, changelog=2, document=4, git=10, nl=7, system=6, todo=3
Demo jawnie wyłącza LLM dokumentacji i podsumowania, więc nie korzysta z
prywatnego .env, sieci ani fallbacku. Każdy audyt zawiera runtimeVersion, requested/effective
mode, model, czas, licznik rekordów/ostrzeżeń, powód i bezpieczne parametry;
apiKey nigdy nie jest zapisywany.
make demo jest celowo deterministyczne. Aby uruchomić pełny pipeline
semantyczny z prawdziwym OpenRouterem i bez możliwości ukrycia błędu
fallbackiem, ustaw klucz w prywatnym .env i uruchom:
make demollmTarget używa LLM dla NL, TODO/CHANGELOG, dokumentacji, komunikacji, syntezy
zadań i podsumowania. Kończy się sukcesem tylko wtedy, gdy manifest potwierdza
succeeded / llm / degraded=false oraz metadane odpowiedzi dla każdego z tych
sześciu etapów. Szczegółowy przepływ, diagram sekwencji i opis artefaktów są w
docs/DEMOLLM.md.
Artefakty trafiają do examples/.intent-demo-llm. Manifest zawiera model,
provider, response ID, czas, tokeny i koszt, ale nie zawiera klucza, promptu
ani surowej odpowiedzi modelu.
Zweryfikowany przebieg z 2026-07-30:
demollm PASS: 20260730T185205Z-312a0535
naturalLanguageExtraction: deepseek/deepseek-v4-flash · llm
markdownExtraction: qwen/qwen3.7-plus · llm
documentationExtraction: qwen/qwen3.7-plus · llm
communicationAnalysis: deepseek/deepseek-v4-flash · llm
taskSynthesis: qwen/qwen3.7-plus · llm
summary: qwen/qwen3.7-flash · llm
Wnioski task synthesis i summary używają generatora wersji 2. Runtime wiąże
ich recordIds wyłącznie z rekordami cytowanych diagnostyk, a nieznany
diagnosticId nadal powoduje błąd require-llm. Puste klucze lokalne
propozycji są nadawane deterministycznie i nie trafiają do publicznego DSL.
Brak klucza, timeout, niepoprawny kontrakt albo zdegradowany etap daje błąd.
Polecenie jest kosztowym testem live; walidacja offline pozostaje w make demo
i npm run verify.
Uruchom backend:
npm run a2aNastępnie otwórz http://localhost:8787/ui. Widok pobierze historię z
GET /api/runs, domyślnie wybierze dwa ostatnie kompletne runy i pokaże ich
diff SVG. Stan serwera można sprawdzić przez:
curl -fsS http://localhost:8787/healthz
# {"status":"ok","service":"todo2code","protocol":"A2A","version":"1.0"}Ten sam runtime jest dostępny przez SDK. Przykład TypeScript wykonuje deterministyczne NL → DSL i sprawdza audyt, zamiast zakładać, że LLM zadziałał:
import { Todo2CodeClient } from 'todo2code/sdk';
const client = new Todo2CodeClient({ baseUrl: 'http://localhost:8787' });
const result = await client.extractNl('TASK.md', '.', 'deterministic');
console.log(result.records.length); // 10 dla bieżącego TASK.md
console.log(result.audit?.status); // succeeded
console.log(result.audit?.effectiveMode); // deterministic
console.log(result.audit?.runtimeVersion); // 0.5.0
console.log(result.audit?.configuration); // bez apiKeyOdpowiedniki extractNl/extractDocs są dostępne również w Pythonie, Go,
Ruście i PHP; kompletne uruchamialne przykłady znajdują się w sdk/*/examples/.
require-llm nigdy nie przechodzi po cichu na parser deterministyczny. Ten
kontrolowany test kończy się kodem procesu 1:
OPENROUTER_API_KEY= T2C_NL_MODE=require-llm \
node dist/src/cli.js pipeline examples \
--task task.md --todo TODO.md --changelog CHANGELOG.md \
--no-docs-llm --out .intent-failure-demoMimo błędu powstaje examples/.intent-failure-demo/runs/<run-id>/manifest.json:
{
"status": "failed",
"failure": {
"stage": "naturalLanguageExtraction",
"code": "LLM_NOT_CONFIGURED",
"message": "OPENROUTER_API_KEY is not configured"
},
"graphFingerprint": null,
"files": {}
}Manifest zachowuje pełny audyt nieudanego etapu i wersję runtime, ale nie
publikuje nieistniejącego grafu ani nie zmienia latest.json. Przy błędnym ID
modelu kod LLM_INVALID_MODEL zawiera dodatkowo aktualną, posortowaną listę ID
z endpointu OpenRouter /models.
Pełny pipeline bez połączeń LLM (również wtedy, gdy lokalny .env zawiera klucz):
node dist/src/cli.js pipeline examples \
--task task.md \
--todo TODO.md \
--changelog CHANGELOG.md \
--docs 'docs/**/*.md' \
--nl-mode deterministic \
--markdown-mode deterministic \
--no-docs-llm \
--no-summary-llm \
--out .intent-demoPełny pipeline z OpenRouter:
# w .env:
# OPENROUTER_API_KEY=...
# T2C_NL_MODE=require-llm
# T2C_MARKDOWN_MODE=require-llm
# T2C_COMMUNICATION_MODE=require-llm
# OPENROUTER_MODEL=mistralai/codestral-2508
# Stage-specific OPENROUTER_*_MODEL variables may override this default.
node dist/src/cli.js pipeline /ścieżka/do/repo \
--task project/ticket-014/README.md \
--todo TODO.md \
--changelog CHANGELOG.md \
--docs 'README.md,docs/**/*.md,project/**/*.md'Tryb ciągły skanuje repozytorium deterministycznie i generuje raport najwyżej raz na wskazany interwał:
node dist/src/cli.js watch . \
--interval 60 \
--scan-interval 2 \
--no-docs-llm \
--out .intentWatcher scala reguły z .gitignore, .dockerignore i .intentignore, pomija
symlinki oraz po raporcie odświeża snapshot, więc własne artefakty nie tworzą
pętli. t2c init instaluje bazowy .intentignore; --no-initial-report
pozwala czekać na pierwszą rzeczywistą zmianę.
t2c init [root]
t2c doctor
t2c extract nl <file> [--root .] [--out nl.intent.jsonl]
t2c extract git [--root .] [--count 10] [--out git.intent.jsonl]
t2c extract ast [root] [--out ast.intent.jsonl]
t2c extract config [root] [--out configuration.intent.jsonl]
t2c extract markdown [--todo TODO.md] [--changelog CHANGELOG.md] [--markdown-mode deterministic|prefer-llm|require-llm]
t2c extract docs [--patterns 'README.md,docs/**/*.md']
t2c link <*.intent.jsonl>... --out intent.graph.json
t2c diagnose intent.graph.json --out diagnostics.json
t2c diff before.graph.json after.graph.json --out graph.diff.json --svg graph.diff.svg
t2c diff --mode files before.ts after.ts --svg files.diff.svg --html files.diff.html
t2c diff --mode git . --rev HEAD --svg worktree.diff.svg
t2c reality intent.graph.json --diagnostics diagnostics.json --svg reality.svg --md reality.md
t2c summarize intent.graph.json --diagnostics diagnostics.json --mode require-llm --out team-summary.md
t2c watch [root] [--interval 60] [--scan-interval 2] [--task TASK.md|none] [--no-summary-llm] [--no-initial-report]
t2c compare-workspace [root] [--base origin/main] [--task TASK.md] [--docs-llm]
t2c propose-code-change intent.graph.json --diagnostics diagnostics.json --out plans.json
t2c propose-source-patch plan.json --out source-patch.json
t2c apply-source-patch source-patch.json --actor reviewer --approval-hash <patchHash>
t2c evaluate-code-change plan.json --before-graph before.json --after-graph after.json --out acceptance.json
t2c close-code-change plans.json --before-graph before.json --after-graph after.json --out close.json
t2c pipeline [root] --task TASK.md --todo TODO.md --changelog CHANGELOG.md
t2c mcp
t2c a2a
extract nl, extract markdown, extract communication, extract docs i summarize mogą korzystać z
OpenRouter. Dla NL, Markdown, komunikacji, summarize i bezpośredniej syntezy
TODO domyślny require-llm kończy operację błędem przy braku klucza, timeoutcie
lub odrzuconej odpowiedzi. prefer-llm trzeba wybrać jawnie, aby dopuścić
oznaczony fallback, a deterministic świadomie pomija sieć. W Markdown LLM nie może zmienić checkboxa, lifecycle,
wersji, daty, kategorii ani provenance — wzbogaca wyłącznie semantykę wpisu.
--communication-mode deterministic zachowuje komunikację lokalnie bez sieci;
tryby LLM tworzą uziemioną syntezę per uczestnik bez oddawania modelowi kontroli nad
identity, rolą, ticketem, źródłem, lifecycle lub klasą epistemiczną.
Dokumentacja bez klucza jest pomijana, a t2c summarize --mode deterministic
świadomie nie wykonuje żądania sieciowego. Dawne --fallback pozostaje aliasem
zgodności, ale nowe integracje powinny używać --mode.
Etap dokumentacji ma osobne limity fragmentu, liczby fragmentów, rekordów,
współbieżności i timeoutu (T2C_DOC_*). Najpierw analizuje fragmenty pasujące
do ścieżek, symboli, ticketów i wersji wykrytych w pozostałych źródłach; obcięcie
budżetu zapisuje ostrzeżenie DOC_CHUNK_BUDGET.
Deterministyczny AST i podział dokumentów korzystają z przyrostowego cache'u
<outputDir>/cache/v1, kluczowanego ścieżką, hashem treści oraz wersjonowanymi
parametrami ekstraktora. Uszkodzony lub niedostępny wpis jest pomijany i
odtwarzany ze źródła. Cache nie przechowuje odpowiedzi OpenRouter; dokument
przy cache-hit nadal przechodzi bieżące wywołanie providera.
Każdy rekord t2c.intent/v1 zawsze zawiera runtime-owned
metadata.generation: generator i jego wersję, wersję todo2code, tryb żądany i
użyty oraz stan fallbacku. Rekord LLM dodatkowo wymaga providera, rozstrzygniętego
modelu i response ID; rekord deterministyczny ma te trzy pola jawnie równe
null. Brak lub niespójna provenance jest błędem kontraktu, a nie opcjonalną
metadaną. Pełny kształt opisuje docs/DSL.md.
Porównanie nie wykonuje checkoutu w katalogu użytkownika. Runtime rozwiązuje bazę do pełnego SHA, tworzy prywatny tymczasowy Git worktree i uruchamia ten sam TypeScript pipeline na bazie oraz aktualnym filesystemie:
node dist/src/cli.js compare-workspace . --base origin/main --out .intentStan workspace obejmuje lokalne commity, indeks, zmiany unstaged i pliki
untracked. Wynik t2c.workspace-comparison/v1 zawiera ahead/behind, listę
zmienionych plików, diff rekordów i relacji oraz zmianę metryk Intent vs Reality:
pełne alignmentRate, pokrycie deklarowanej intencji implementacją, udział kodu
posiadającego plan i dokumentację, gaps oraz liczniki diagnostyk. Trend może być
improved, regressed, mixed albo unchanged. Artefakty trafiają do:
.intent/comparisons/<comparison-id>/
├── comparison.json
├── trend.md
├── intent-diff.svg
├── base.graph.json
├── workspace.graph.json
├── base-reality.md
├── workspace-reality.md
└── workspace-reality.svg
Narracyjne podsumowania obu przebiegów są zawsze deterministyczne i nie wykonują
zbędnych zapytań LLM. Dokumentacja LLM po obu stronach jest opcjonalna, ponieważ
podwaja liczbę zapytań i może wprowadzać niedeterministyczny szum. Jeśli podano
--task, ekstrakcja NL respektuje T2C_NL_MODE i jest osobno audytowana:
t2c compare-workspace . --base origin/main --docs-llm \
--docs 'README.md,docs/**/*.md,.intent/runs/<run-id>/team-summary.md' \
--doc-excludes 'node_modules/**,.git/**,dist/**,TODO.md,CHANGELOG.md'Usunięcie .intent/** z --doc-excludes jest wymagane tylko dla jawnie
wskazanego historycznego raportu. Nie należy używać szerokiego .intent/**/*.md,
bo bieżące raporty zaczęłyby zasilać kolejne runy.
t2c watch pilnuje lokalnych zmian i generuje świeży raport najwyżej raz na minutę:
node dist/src/cli.js watch . --no-docs-llm --no-summary-llmIstniejący TASK.md jest czytany domyślnie; --task none wyłącza to źródło.
Opcja --no-summary-llm eliminuje sieciowy etap podsumowania z każdego cyklu.
Obowiązują dwa niezależne czasy:
| Opcja | Domyślnie | Znaczenie |
|---|---|---|
--scan-interval |
2 s | jak szybko zmiana zostaje zauważona |
--interval |
60 s | minimalny odstęp między dwoma raportami |
Zmiany napływające częściej niż --interval są kumulowane, a nie kolejkowane: po
upływie progu powstaje jeden raport obejmujący wszystko, co się zmieniło. Raport
nigdy nie startuje, gdy poprzedni jeszcze trwa, więc wolny pipeline nie tworzy
nakładających się runów. --no-initial-report pomija raport startowy i czeka na
pierwszą realną zmianę.
Detekcja opiera się na cyklicznym skanowaniu (rozmiar + mtime), a nie na
fs.watch, który zależy od platformy i gubi zdarzenia pod obciążeniem. Skan jest
tani, bo katalogi wykluczone są odcinane przed odczytem — node_modules nigdy
nie jest czytane.
Watch pomija ścieżki wymienione w trzech plikach, czytanych w tej kolejności:
.gitignore.dockerignore.intentignore
Późniejszy plik wygrywa, więc .intentignore może przywrócić ścieżkę przez !wzorzec.
.intentignore jest zakładany przez t2c init i wyklucza m.in. wszystkie katalogi
kropkowe (.*/ — .git, .idea, .venv, .github, .cache), katalog .intent/
z własnymi raportami, wyjścia buildu (node_modules/, dist/, target/,
__pycache__/), lockfile'e oraz logi i pliki tymczasowe.
Składnia jest zgodna z gitignore: komentarze #, negacja !, końcowy /
ogranicza regułę do katalogów, wzorzec bez ukośnika dopasowuje się na dowolnej
głębokości, a ** przechodzi przez katalogi. Reguły .dockerignore są
interpretowane tą samą semantyką, czyli nieco szerzej niż robi to Docker
(kotwiczący wzorce do korzenia kontekstu) — wpisy w tym pliku nazywają wyjścia
buildu, więc wykluczenie zagnieżdżonej kopii jest zamierzone.
.intent/
├── latest.json
└── runs/<run-id>/
├── nl.intent.jsonl
├── git.intent.jsonl
├── ast.intent.jsonl
├── todo.intent.jsonl
├── changelog.intent.jsonl
├── document.intent.jsonl
├── intent.graph.json
├── diagnostics.json
├── summary-conclusions.json
├── team-summary.md
└── manifest.json
Każdy rekord zawiera identyfikator, statement, lifecycle, dokładne źródło, hash treści, klasę epistemiczną, confidence i podstawy wnioskowania. Fakty AST mają confidence 1.0. Rekordy wygenerowane przez LLM są oznaczone jako llm_inference i mają pułap zależny od struktury źródła: 0.94 dla wzbogaconych pozycji TODO/CHANGELOG, 0.90 dla prozy NL i 0.85 dla dokumentacji. Żaden z nich nie sięga poziomu obserwacji deterministycznej — pełną tabelę zawiera docs/DSL.md.
summary-conclusions.json jest strukturalnym źródłem raportu: zawiera wyłącznie
zwalidowane t2c.conclusion/v1, a team-summary.md jest jego deterministyczną
projekcją połączoną z sekcjami faktów grafu. manifest.json zapisuje również
runtime.version, bezpieczny snapshot i
fingerprint konfiguracji oraz statusy naturalLanguageExtraction,
markdownExtraction, documentationExtraction i summary. Status runu degraded jest pokazywany
w CLI, GET /api/runs i UI. Parametry obejmują modele, timeout, temperaturę,
limit tokenów, budżet dokumentów, konfigurację adapterów i tryb structured
output; klucz API nigdy nie jest zapisywany. Odpowiedzi LLM zapisują zwrócone
przez provider responseId, resolved model/provider oraz usage/cost. Każdy
audyt ekstrakcji zawiera też wersję runtime i bezpieczne parametry. Każda awaria
pipeline po utworzeniu runu tworzy manifest status=failed z kodem i etapem, ale bez
nieistniejącego grafu ani aktualizacji latest.json.
Uruchomienie serwera stdio:
node dist/src/interfaces/mcp.jsPrzykładowa konfiguracja hosta MCP:
{
"mcpServers": {
"todo2code": {
"command": "node",
"args": ["/absolute/path/todo2code/dist/src/interfaces/mcp.js"],
"env": {
"T2C_ROOT": "/absolute/path/workspace",
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
}
}
}
}Dostępne narzędzia: extract_nl, extract_git, extract_ast, extract_config, extract_markdown, extract_docs, extract_communication, analyze_communication, link, diagnose, diff, diff_files, diff_git, reality, compare_workspace, summarize, pipeline, propose_todo, render_todo, apply_todo. Serwer udostępnia też zasoby t2c://latest/*, w tym analizę komunikacji i artefakty review/apply.
Porównanie dwóch grafów zwraca kanoniczny t2c.diff/v1 z rekordami added, removed, changed i liczbą elementów bez zmian. --mode files tworzy deterministyczny diff linii t2c.filediff/v1, a --mode git stosuje ten sam silnik do rewizji, indeksu lub drzewa roboczego. Dostępne są widoki SVG, HTML oraz unified diff; nie wymagają bibliotek renderujących i nie wykonują treści pochodzącej z plików.
Polecenie t2c reality projektuje pojedynczy graf do t2c.reality/v1: zestawia deklaracje z taska, TODO i dokumentacji z faktami Git/AST, a rozbieżności pokazuje jako SVG albo tabelę Markdown.
Po uruchomieniu A2A dostępne są:
- frontend:
http://localhost:8787/ui— pobiera historię z.intent/runs, domyślnie wybiera dwa najnowsze kompletne runy i automatycznie pokazuje ich diff SVG; - historia runów:
GET http://localhost:8787/api/runs; - REST diff:
POST http://localhost:8787/api/diff; - A2A/MCP action:
diff.
POST /api/diff domyślnie zwraca pełny t2c.diff/v1. Ustawienie compact: true
zwraca projekcję przeznaczoną dla UI: fingerprinty, liczniki summary i opcjonalny
SVG, bez pełnych tablic rekordów oraz relacji.
SDK TypeScript/JavaScript:
import { Todo2CodeClient } from 'todo2code/sdk';
const client = new Todo2CodeClient({ baseUrl: 'http://localhost:8787' });
const result = await client.diffGraphs(beforeGraph, afterGraph);
console.log(result.diff.summary, result.svg);
const files = await client.diffTextFiles('before.ts', 'after.ts', { includeHtml: true });
const reality = await client.reality(afterGraph);
const comparison = await client.compareWorkspace({ root: '.', base: 'origin/main' });SDK Python nie ma zewnętrznych zależności:
from sdk.python import Todo2CodeClient
client = Todo2CodeClient("http://localhost:8787")
result = client.diff_graphs(before_graph, after_graph)
print(result["diff"]["summary"])
files = client.diff_text_files("before.ts", "after.ts", include_html=True)
reality = client.reality(after_graph)
comparison = client.compare_workspace(root=".", base="origin/main")Można go także zainstalować przez python3 -m pip install ./sdk/python i importować jako todo2code_sdk.
Uruchamialne przykłady znajdują się w examples/sdk/typescript.mjs i examples/sdk/python.py.
Pomiary oraz bezpieczne i semantycznie istotne dalsze optymalizacje opisuje docs/OPTIMIZATION.md.
Katalog sdk/ zawiera pełne klienty A2A v1.0 udostępniające wszystkie akcje runtime'u (nie tylko diff), wraz z typami Intent DSL:
| Język | Katalog | Zależności | Klasa |
|---|---|---|---|
| TypeScript / Node | sdk/typescript/ |
brak | T2CClient |
| Python 3.10+ | sdk/python/ |
brak | T2CClient |
| Go 1.21+ | sdk/go/ |
brak | todo2code.Client |
| Rust 1.70+ | sdk/rust/ |
serde_json |
todo2code::Client |
| PHP 8.1+ | sdk/php/ |
brak | Todo2Code\Client |
Każdy język ma uruchamialny przykład w sdk/<język>/examples/. Wszystkie przepuszczają ten sam zbiór rekordów przez link i muszą otrzymać identyczny fingerprint grafu — to test wierności round-tripu typów. Szczegóły: sdk/README.md.
Python udostępnia także lokalny TypeScriptRuntime. Nie kopiuje implementacji
DSL do Pythona, tylko uruchamia przez Node.js skompilowany dist/src/cli.js:
make python-wheel
python3 -m pip install .intent-packages/python/todo2code_sdk-*.whl
T2C_TYPESCRIPT_CLI="$PWD/dist/src/cli.js" python3 sdk/python/examples/local_runtime.pyMost obsługuje pipeline, diagnose, graph diff oraz reality bez serwera
A2A. Szczegóły i przykład API: sdk/python/README.md.
examples/backend (HTTP API bez zależności) i examples/frontend (panel DOM bez frameworka) to gotowe wejścia dla runtime'u DSL. Każde ma task.md, TODO.md, CHANGELOG.md, README.md i src/, i celowo zawiera rozbieżności plan↔kod, żeby t2c reality miał co pokazać:
node dist/src/cli.js pipeline examples/backend \
--task task.md --todo TODO.md --changelog CHANGELOG.md \
--docs 'README.md' --no-docs-llm --out .intent
node dist/src/cli.js reality examples/backend/.intent/runs/<run-id>/intent.graph.json \
--diagnostics examples/backend/.intent/runs/<run-id>/diagnostics.json \
--svg reality.svg --md reality.mdnode dist/src/interfaces/a2a.jsAgent Card:
curl http://localhost:8787/.well-known/agent-card.jsonUruchomienie pipeline przez SendMessage:
curl -s http://localhost:8787/a2a \
-H 'Content-Type: application/json' \
-H 'A2A-Version: 1.0' \
-d '{
"jsonrpc":"2.0",
"id":"req-1",
"method":"SendMessage",
"params":{
"message":{
"messageId":"msg-1",
"role":"ROLE_USER",
"parts":[{
"data":{
"action":"pipeline",
"input":{
"root":".",
"task":"TASK.md",
"includeDocsLlm":false
}
},
"mediaType":"application/json"
}]
}
}
}'Interfejs A2A jest v1-only: nagłówek A2A-Version: 1.0 (albo parametr zapytania o tej nazwie) jest wymagany. Brak nagłówka oznacza protokół 0.3 i jest odrzucany kodem -32009; aliasy metod v0.3 nie są przyjmowane. GetTask i CancelTask zwracają task bez wrappera, a ListTasks obsługuje filtry, cursor pagination, historyLength oraz includeArtifacts (domyślnie false).
Ustawienie T2C_A2A_TOKEN włącza Bearer authentication i izolację tasków według principalu. Domyślnie MCP i A2A nie mogą analizować ścieżek poza T2C_ROOT; wyjątek wymaga jawnego T2C_ALLOW_OUTSIDE_ROOT=true.
Domyślny task store A2A pozostaje pamięciowy. Aby zachować taski po restarcie i współdzielić je między replikami używającymi tego samego wolumenu, ustaw:
T2C_A2A_TASK_STORE=.intent/a2a-tasks.jsonSnapshot jest zapisywany atomowo z uprawnieniami 0600. Blokada katalogowa
chroni idempotency i aktualizacje między procesami; ścieżka podlega tym samym
ograniczeniom T2C_ROOT co pozostałe operacje runtime'u.
Runtime używa POST /api/v1/chat/completions. Wszystkie etapy semantyczne
proszą o response_format: json_schema, wymuszają
provider.require_parameters, a przy braku wsparcia endpointu próbują
kontrolowanego fallbacku json_object. Opcjonalny plugin response-healing
jest sterowany przez .env. Osobny OPENROUTER_TASK_MODEL wybiera model dla
graf + diagnostyka → zadania i domyślnie dziedziczy OPENROUTER_MODEL.
Domyślny mistralai/codestral-2508 przeszedł pełną kontrolę live 6/6: 57,129 s,
118 920 tokenów i $0.037994, bez fallbacku lub degradacji. Na tym samym
kontrakcie google/gemini-3-flash-preview również przeszedł 6/6, a
deepseek/deepseek-v4-pro przekroczył 900-sekundowy budżet. Każdy
bezpośredni ekstraktor wykonuje najwyżej jedną próbę korekcyjną po odrzuceniu
odpowiedzi i ponownie podaje dokładny JSON Schema; walidacja pozostaje taka
sama, a obie odpowiedzi zachowują model, providera, tokeny i koszt w audycie.
Wszystkie siedem produkcyjnych granic structured output używa jednego
kanonicznego kontraktu na etap: z niego powstaje schema wysyłana do providera i
parser TypeScript wykonywany przed odczytem odpowiedzi. Runtime odrzuca obce
pola, brakujące klucze, typy i wartości poza zakresem bez ich semantycznego
„naprawiania”; uziemienie cytowań jest następną, osobną kontrolą. Polecenia
npm run verify:structured-responses i npm run verify:schemas blokują powrót
driftu oraz nieaktualny publikowany schemat dokumentów.
Klucz nie jest zapisywany do artefaktów, logów ani odpowiedzi MCP/A2A. doctor pokazuje jedynie status configured/not configured.
Ten sam etap jest dostępny przez CLI i publiczne API TypeScript:
node dist/src/cli.js propose-todo .intent/runs/<run>/intent.graph.json \
--diagnostics .intent/runs/<run>/diagnostics.json \
--mode require-llm --out .intent/runs/<run>/task-synthesis.jsonOdpowiedniki render-todo i apply-todo opisuje
docs/CLI_GUIDE.md. API biblioteki pozostaje dostępne:
import { readFile } from 'node:fs/promises';
import { getConfig, synthesizeTodoProposals } from 'todo2code';
const graph = JSON.parse(await readFile('.intent/runs/<run>/intent.graph.json', 'utf8'));
const diagnostics = JSON.parse(await readFile('.intent/runs/<run>/diagnostics.json', 'utf8'));
const result = await synthesizeTodoProposals(graph, diagnostics, getConfig(), 'require-llm');
console.log(JSON.stringify(result, null, 2));W prefer-llm awaria daje puste conclusions/proposals i osobne
rawDiagnosticActions; nie są one oznaczane jako wynik semantycznej syntezy.
writeTodoPatchArtifacts przyjmuje wyłącznie zwalidowane newProposalIds i
zapisuje obok siebie czytelny TODO.patch oraz audyt TODO.patch.json.
Renderer zachowuje kolejność zależność-przed-zadaniem, grupuje kolejne zadania
według P0–P3 i pokazuje kryteria akceptacji, targety, zależności oraz wszystkie
ID dowodów. Nie modyfikuje źródłowego TODO.md.
import { applyTodoPatch, writeTodoPatchArtifacts } from 'todo2code';
const written = await writeTodoPatchArtifacts({
directory: '.intent/runs/<run>',
todoPath: 'TODO.md',
todoContent,
graph,
diagnostics,
conclusions: result.conclusions,
proposals: result.proposals,
validation: result.validation,
synthesisAudit: result.audit,
});
// Człowiek najpierw przegląda written.patchPath i kopiuje hash z audytu.
await applyTodoPatch({
todoPath: 'TODO.md',
patchPath: written.patchPath,
auditPath: written.auditPath,
receiptPath: '.intent/runs/<run>/TODO.patch.receipt.json',
approval: { actor: 'reviewer@example.com', patchHash: written.artifact.renderedPatchHash },
});Apply odrzuca brak lub błędny hash akceptacji, zmieniony TODO.md i zmieniony
patch. Aktualizacja TODO.md używa pliku tymczasowego, fsync i atomowego
rename, zachowując dotychczasowe prawa pliku. Receipt zapisuje aktora, czas,
hash źródła, patcha i wyniku. Powtórzenie tej samej operacji zwraca wynik
idempotentny bez ponownego dopisania. Jeżeli proces zakończy się po rename, ale
przed zapisem receipt, następne wywołanie rozpozna dokładny suffix i hash
oryginału, po czym bezpiecznie odtworzy receipt. Każda inna zmiana wymaga
ponownej syntezy i przeglądu.
NL i Git zawsze mają deterministyczny klasyfikator słownikowy. Lokalny model TensorFlow można włączyć przez:
T2C_ENABLE_TF=true
T2C_TF_MODEL_PATH=/models/action/model.json
T2C_TF_MODULE_PATH=adapters/tensorflow/node_modules/@tensorflow/tfjs-node/dist/index.js
T2C_TF_LABELS=add,fix,remove,refactor,test,document,configure,analyze,unknownNajpierw należy wykonać make install-tf. Obok model.json musi znajdować się
vocabulary.json, czyli mapa token → indeks. Model powinien przyjmować tensor
[1, vocabulary_size] i zwracać rozkład klas. Przy braku adaptera lub błędzie
modelu runtime wraca do heurystyk i zapisuje heuristic_fallback:<powód>.
make setup
make verify
make demo
make docker-build
make docker-smoke
make docker-up
make e2e-core
make e2e-fullProdukcyjny docker-compose.yml montuje repozytorium
T2C_WORKSPACE pod /workspace, wystawia kontenerowy port 8787 jako
T2C_DOCKER_HOST_PORT i zachowuje .intent w analizowanym workspace. Przy
zmianie portu hosta należy odpowiednio ustawić również publiczny
T2C_A2A_PUBLIC_URL oraz kliencki T2C_A2A_URL.
DOCKER_SMOKE_IMAGE pozwala zmienić lokalny tag używany przez smoke test.
Osobny compose.e2e.yml używa Dockerfile.e2e i nie montuje hosta. Profil
core testuje Node/Python, a full dodaje Go 1.23, JDK 17, Rust 1.85 i PHP,
odrzuca skipy oraz wymaga zgodności przykładów wszystkich pięciu SDK. Stabilne
kody T2C-E2E-*, zakres bramek i sposoby naprawy opisuje
docs/E2E.md.
Wbudowane klasy obejmują m.in.:
PLANNED_NOT_IMPLEMENTED;IMPLEMENTED_NOT_PLANNED;IMPLEMENTED_NOT_DOCUMENTED;CHANGELOG_WITHOUT_IMPLEMENTATION;CONFLICTING_INTENT;AMBIGUOUS_REQUIREMENT— brakujące pole, wieloznaczny symbol lub konflikt symbolu ztarget.path, wraz z konkretną sugerowaną poprawką;UNLINKED_RECORD.
ALIGNED oznacza wyłącznie brak wykrytej blokującej rozbieżności w dostępnych źródłach. Nie nadaje automatycznie statusu DONE i nie zastępuje decyzji człowieka.
docs/PIPELINE_DSL_NL.md— diagramy krok po kroku: zbiory → konwertery → Intent DSL → graf → wnioski → raport NL;docs/ARCHITECTURE.md— komponenty i przepływ;docs/DSL.md— model danych i relacje;docs/REQUIREMENTS.md— śledzenie wymagań;docs/PROTOCOLS.md— MCP, A2A i OpenRouter;docs/SECURITY.md— granice dostępu i sekretów;docs/VALIDATION.md— zakres oraz wynik walidacji paczki;docs/OPTIMIZATION.md— zmierzone wąskie gardła runtime'u i zastosowane usprawnienia;docs/CODE_CHANGE_PLANS.md— ugruntowany plan zmiany kodu i bramka acceptance po ponownej analizie;docs/READINESS.md— ocena gotowości, zmierzone luki i kryteria wydania;sdk/README.md— SDK dla TypeScript, Pythona, Go, Rusta i PHP;docs/reference/original-monitoring-design.md— materiał wejściowy dostarczony do projektu.
Projekt jest udostępniany na warunkach Apache License 2.0.
Licensed under Apache-2.0.
