Commit Graph

214 Commits

Author SHA1 Message Date
Dobromir Popov
fff11c4d8b feat(us-024): enhanced availability map with per-node health details
Coverage endpoint now skips node purge so dead nodes remain visible.
Each band in /v1/coverage/<model> includes a `nodes` array with per-node
health: alive status, last_seen_seconds_ago, heartbeat_success_rate,
inference_success_rate, queue_depth, uptime_seconds, and endpoint.
Updated tests to assert new band structure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 13:28:12 +03:00
Dobromir Popov
a4373a6202 Merge branch 'master' of https://git.d-popov.com/popov/neuron-tai 2026-06-30 12:22:58 +02:00
Dobromir Popov
ad3368f7ea docs 2026-06-30 12:22:21 +02:00
Dobromir Popov
34fb1ec65d feat(us-023): heartbeat stats payload, request counters, dynamic reassignment response
Node now sends cumulative stats in heartbeat body:
  total_requests, failed_requests, queue_depth, uptime_seconds, status
Stats are tracked thread-safely in _TorchHTTPServer; buffered locally during
outage streak and flushed on next successful heartbeat.

Tracker stores stats on _NodeEntry (total_requests, failed_requests,
queue_depth, uptime_seconds, status, heartbeats_expected/received) and
returns new_assignment in heartbeat response when pending_new_assignment is set.

Node logs received new_assignment (hot-reload wired in US-026).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 13:20:52 +03:00
Dobromir Popov
96af82892f feat(us-022): X-Meshnet-Start-Layer pipeline protocol for overlapping shards
When _select_route picks two nodes with overlapping registrations (e.g.
A:0-22 and B:20-24), the tracker now injects start_layer per hop so B
executes only layers 23-24, not 20-24.

- model_backend: forward_bytes + _run_layers accept start_layer offset;
  clamped to shard_start to prevent out-of-bounds indexing
- torch_server: _handle_binary_forward reads X-Meshnet-Start-Layer header;
  _run_downstream_pipeline sends it per hop; route is now list[tuple[str,int]]
- server: proxy injects {endpoint, start_layer} objects in X-Meshnet-Route;
  /v1/route response includes start_layer per node in the nodes list
- test: fake backends accept start_layer=None kwarg

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 13:14:45 +03:00
Dobromir Popov
e1ba120912 feat(us-021): --route-timeout CLI flag for node tracker route lookup
Default 30s replaces the hardcoded 5s. Wired through TorchNodeServer →
_TorchHTTPServer → _get_remaining_route. Available on both the legacy
`start` subcommand and the default wizard path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 13:06:00 +03:00
Dobromir Popov
c691e8d5d1 fix inference 2026-06-30 13:01:29 +03:00
Dobromir Popov
dade97ee67 feat(us-016/us-017): mining-style node startup CLI, live dashboard, auto-shard, P2P gossip + TLS
Merges worktree-feat+us-016 into master. Combined both sets of _NodeEntry
fields: hf_repo/num_layers (HEAD) and relay_addr/cert_fingerprint/peer_id
(US-017). Kept HEAD's auto-shard tracker query and shard_label formatting.

US-016: mining-style startup CLI with live ASCII dashboard, hardware
detection, auto-shard range detection from model layer count, tracker
network-assign integration for gap-filling.

US-017: P2P gossip protocol, NAT-traversal relay node, TLS peer
authentication via cert fingerprint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 12:30:02 +03:00
Dobromir Popov
2e1e0ae172 fix(us-020): silence BrokenPipeError in tracker _send_json; deterministic node IDs; HF model coverage
- Wrap wfile.write in _TrackerHandler._send_json with except BrokenPipeError
- Replace uuid4 node IDs with deterministic SHA-256 hash of endpoint+model+shards
  so nodes keep the same ID on re-registration after tracker restart
- /v1/models now lists HF-repo models (not just preset models)
- /v1/coverage/{model} now resolves HF repos, not just preset names
- /v1/route response includes node_id alongside endpoint
- startup.py exposes tracker_node_id on node object and prints it in dashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 12:26:50 +03:00
Dobromir Popov
4a803377dc perf: tracker injects pre-resolved route; node skips redundant tracker query
When the tracker proxies /v1/chat/completions to a first-shard node it
already holds the full registry picture. It now resolves the downstream
route inline via _select_route, strips the proxied node, and sends the
result as X-Meshnet-Route header alongside the request body.

The first-shard node reads this header in _get_remaining_route and
returns it directly, skipping the second tracker HTTP call entirely.
Falls back to the tracker query transparently when the header is absent
(direct node-to-node calls or older tracker versions).

Reduces per-inference tracker round-trips from 2 to 1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 10:44:18 +03:00
Dobromir Popov
ae5ff6a805 feat: tracker exposes OpenAI-compatible /v1/chat/completions proxy
The tracker is now the single entrypoint for inference. Clients POST to
the tracker's /v1/chat/completions and it forwards to a live tracker-mode
(first-shard) node for the requested model, applying round-robin load
balancing across multiple first-shard nodes when available.

Streaming (text/event-stream) is relayed chunk-by-chunk. Non-streaming
responses are buffered and forwarded. BrokenPipeError on client disconnect
is silenced. Upstream errors relay the original HTTP status and body.

Also adds GET /v1/health → {"status": "ok"} on the tracker.

Usage:
  curl -s http://tracker:8081/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{"model":"Qwen/Qwen2.5-0.5B-Instruct","messages":[...]}'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 10:21:33 +03:00
Dobromir Popov
b95e25a5c3 fix: silence BrokenPipeError on slow CPU inference, raise downstream timeout
BrokenPipeError on wfile.write is harmless — the client disconnected
before the response arrived. Suppress it instead of printing a full
traceback to stderr.

Raise the downstream pipeline timeout from 10s to 120s so the Windows
node (or any caller) waits long enough for CPU-mode inference to
complete before giving up.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 10:01:37 +03:00
Dobromir Popov
748d535c46 feat(us-019): distributed tracker consensus — Raft assignments + CRDT gossip
raft.py: minimal Raft consensus for shard-assignment log
  - Leader election with random 150–300ms election timeouts
  - AppendEntries log replication; majority commit required
  - RequestVote RPC with log-completeness check
  - Follower registration forwarded to leader via HTTP proxy

gossip.py: LWW CRDT gossip for inference-node heartbeat liveness
  - Each tracker keeps {node_id → wall_clock_timestamp}
  - Merges incoming gossip by taking max per key
  - Pushes snapshot to random peer every 3 seconds

server.py + cli.py:
  - TrackerServer gains cluster_peers + cluster_self_url params
  - New HTTP endpoints: /v1/raft/vote, /v1/raft/append,
    /v1/raft/status, /v1/gossip
  - --cluster-peers and --self-url CLI flags

tests/test_tracker_consensus.py: 6 integration tests
  - Leader elected within 1s
  - Follower registration propagated to all nodes
  - Follower proxy to leader
  - Leader kill → new election within 5s, registrations continue
  - Gossip table updated on heartbeat

92 tests pass, 1 skipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 09:05:21 +03:00
Dobromir Popov
bbe57d5f07 fix: advertise LAN IP instead of mDNS hostname when --host 0.0.0.0
socket.getfqdn() returns *.localdomain names that other machines on
the same LAN (especially cross-OS) cannot resolve via DNS. When the
node is bound to 0.0.0.0 and --advertise-host is not given, probe the
outbound IP by connecting a UDP socket toward the tracker — this picks
the correct interface IP without sending any data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 02:27:10 +03:00
Dobromir Popov
0be35d257b fix: robust tracker reconnect — re-register proactively after outage
Previous logic caught 404 on heartbeat and re-registered, but the re-
registration failed silently if the tracker wasn't fully ready yet.

New approach: after any connection-refused streak, the heartbeat loop
switches to re-registration mode and keeps retrying until the tracker
accepts the registration (instead of sending heartbeats into a fresh
registry that doesn't know this node). Falls back to the 404 path for
the case where a node is purged without a full tracker restart.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 02:12:06 +03:00
Dobromir Popov
be37048145 feat(us-018): WSL2 install guide, two-machine LAN test docs, and test script
- docs/INSTALL_WINDOWS.md: step-by-step WSL2 + CUDA + meshnet-node install on
  Windows 11, including port-proxy setup and known issues
- docs/TWO_MACHINE_TEST.md: two-machine LAN test procedure, start order,
  verification steps, latency reading, and Known Issues section
- scripts/test_lan_inference.py: stdlib-only test script; sends 3 chat
  completions, validates OpenAI response format, prints tokens + latency,
  exits 0 on success; auto-discovers gateway from tracker if --gateway omitted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 01:37:33 +03:00
Dobromir Popov
d701ae9ba2 fix: node auto-re-registers with tracker after 404 heartbeat (tracker restart)
When the tracker restarts, nodes' registrations are lost. The heartbeat loop
was catching the 404 and printing a warning but never re-registering, leaving
the node permanently invisible until manually restarted.

Fix: on HTTP 404 heartbeat response, the loop re-posts the original
registration payload to /v1/nodes/register and updates the node_id and
heartbeat URL for subsequent beats. This also handles tracker expiry races.

The register_payload is now passed into _start_heartbeat so the thread has
everything needed for re-registration without reaching back into run_startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 01:15:15 +03:00
Dobromir Popov
1e6016e76f less verbose messages 2026-06-30 01:10:20 +03:00
Dobromir Popov
60ccf47cb4 feat(us-016): fix distributed inference route lookup and autoregressive generation
Route lookup was using the client-provided model name ("qwen2.5-0.5b") but
the tracker registers nodes under their full hf_repo ("Qwen/Qwen2.5-0.5B-Instruct").
This caused a 404 on /v1/route and the non-tail node fell back to the
"no downstream route available" error message.

Fix: _get_remaining_route now uses server.backend.model_id (the actual hf_repo)
for the tracker query. Skips self by port matching rather than blind route[0] drop.
Also prints a warning when route lookup fails so the cause is visible.

Distributed generation was also only producing 1 token (single greedy argmax
in decode_tail). Replaced with an autoregressive loop: head node encodes the
growing sequence and forwards to the downstream shard each step, collecting
one token per iteration up to max_tokens or EOS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 01:07:38 +03:00
Dobromir Popov
c75e9708ae feat(us-016): tracker route for HF models, endpoint dedup, purge logging
Tracker /v1/route now resolves HF model nodes (by hf_repo or short name)
in addition to preset models, using the same greedy interval-cover logic.
This allows distributed inference routing across two nodes each holding
half the model.

Endpoint dedup: re-registering the same endpoint atomically replaces the
old entry so stale registrations don't accumulate across node restarts.

Purge logging: tracker now prints when a node expires due to missed
heartbeats so operators can see dead nodes being removed.

Timing fix: heartbeat timeout raised from 30s to 90s (3 missed beats);
node heartbeat interval lowered from 30s to 20s to maintain margin.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 00:59:15 +03:00
Dobromir Popov
3286e42783 feat(us-016): smart shard gap detection for auto-join and --model-id
Tracker /v1/network/assign now accepts an optional `hf_repo` query param
to restrict assignment to a specific model, and returns `gap_found: bool`
so callers know whether they received a real gap vs a redundancy slot.

Node startup with --model-id (no explicit shard args) now queries the
tracker first for an uncovered gap for that model before defaulting to
full coverage (0..n-1). This means a second node with --model-id will
serve only the missing layers, not the whole model again.

Auto-join fallback (no --model-id) now prints why it fell through
instead of silently switching to stub-model.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 00:48:34 +03:00
Dobromir Popov
97eefd3d5e feat(us-016): connection/heartbeat visibility for tracker and node
Tracker now prints a line when a node registers and on every heartbeat
received. Node prints its assigned node_id after successful registration
and starts a daemon heartbeat thread (30s interval) that logs each send.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 00:41:10 +03:00
Dobromir Popov
a7cc377d13 feat: auto-join network — node discovers missing shards from tracker
Tracker:
- _NodeEntry gains hf_repo + num_layers fields (parsed from register body)
- GET /v1/network/assign — finds the biggest uncovered shard gap across
  registered HF-model nodes; returns {hf_repo, shard_start, shard_end, num_layers}
- Returns 503 when no HF-model nodes are registered yet

Node startup:
- When model_id is set: registers with tracker including hf_repo + num_layers
  so other nodes can auto-join this model
- When model_id is empty/None: queries /v1/network/assign, gets assigned the
  missing layers, loads TorchNodeServer with the assigned shard automatically
- Fixes empty-string model_id leaking from DEFAULTS (treats "" same as None)

Usage: `meshnet-node start --tracker http://localhost:8080 --quantization bfloat16`
Node discovers what to serve and joins the network without any model flags.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 00:22:33 +03:00
Dobromir Popov
1bdfce657d inference working 2026-06-29 23:54:35 +03:00
Dobromir Popov
607d49f5b0 fix: proper autoregressive inference with streaming support
Single-node mode now uses HF model.generate() instead of one-shot
decode_tail(), giving correct multi-token output with KV cache.

model_backend.py:
- generate_text(messages, max_new_tokens, temperature, top_p) — full
  autoregressive generation via model.generate() with chat template
- generate_text_streaming() — yields token strings via TextIteratorStreamer
- _encode_messages() — applies chat template (tokenize=False then tokenize),
  falls back to joining user messages; avoids BatchEncoding issues

torch_server.py:
- _handle_chat_completions: fast path when backend is head+tail — calls
  generate_text() or generate_text_streaming() directly instead of the
  single-token encode_prompt+decode_tail pipeline
- _stream_openai_response: new SSE streaming handler for token iterators
- Parses max_tokens, temperature, top_p from request body
- Distributed path (partial shards) unchanged

Verified: streaming and non-streaming both work with Qwen2.5-0.5B-Instruct.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:46:51 +03:00
Dobromir Popov
6b9caecd90 feat: add US-019 distributed tracker consensus (Raft + CRDT)
Captures the architecture decision: Raft for shard assignments
(strong consistency, leader-elected) + CRDT gossip for node heartbeats
(high-frequency, eventual consistency). Approved 2026-06-29.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:37:33 +03:00
Dobromir Popov
4e292eaaae fix: shard_end convention — inclusive (0-based) not exclusive
model_backend.py was using Python-style exclusive end (layers[start:end])
while all callers (CLI, tests, QUICKSTART) use inclusive 0-based indexing.
Result: 24-layer model with shard_end=23 ran only 23 layers and never
set is_tail=True, so decode_tail() was never called and responses were empty.

- is_tail: == total_layers → >= total_layers - 1
- _run_layers: layers[start:end] → layers[start:end+1]
- Validation: > total_layers → >= total_layers (was also wrong)

Inference confirmed: Qwen2.5-0.5B-Instruct now returns real LLM output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:37:01 +03:00
Dobromir Popov
ded8c06e77 docs: update QUICKSTART to reflect auto-shard detection
No need for --shard-start/--shard-end in the basic start command;
fix layer count for Qwen2.5-0.5B from 28 to 24 (verified via AutoConfig).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:28:23 +03:00
Dobromir Popov
080d49b2c2 feat(us-016): auto-detect shard range from model config
Layer count is now fetched from the curated catalog (zero network calls
for known models) or via AutoConfig.from_pretrained() (~1 KB config.json
only) when model_id is given without --shard-start/--shard-end.

- model_catalog: add detect_num_layers(), two small Qwen models at top
- startup: _detect_num_layers() helper; shard range auto-derived
- wizard: show detected layer count for custom HF repos
- tests: 3 new tests for auto-shard; fix catalog-order assumptions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 18:27:50 +03:00
Dobromir Popov
a2258d3df4 feat(us-017): P2P gossip, NAT-traversal relay node, and TLS
- packages/p2p: identity (peer_id from sha256 of RSA pubkey), TLS cert
  generation with SHA-256 fingerprint, GossipClient (WSS PubSub with
  per-topic handlers, dedup by msg_id, auto-reconnect), MdnsDiscovery
  (zeroconf optional dependency, graceful no-op fallback)
- packages/relay: new meshnet-relay package — RelayServer (asyncio +
  websockets) with gossip fanout hub, circuit relay proxy for NAT traversal,
  peer registry; meshnet-relay CLI
- packages/p2p/relay_bootstrap.json: team relay bootstrap list
- Tracker: _NodeEntry gains relay_addr, cert_fingerprint, peer_id; both
  register and heartbeat handlers read and store these optional fields
- docs/adr/0010 already written (previous commit)
- conftest.py: packages/relay added to sys.path
- 18 new tests; 115 passed total, 1 skipped (no regressions)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 17:58:16 +03:00
Dobromir Popov
65f3ee6a85 feat(us-016): mining-style node startup CLI + live dashboard
- `meshnet-node` with no args runs interactive setup wizard on first run,
  then starts directly on subsequent runs using saved config
- Wizard auto-detects all GPUs/VRAM, shows curated model list with per-quant
  VRAM requirements, marks models that exceed available VRAM as incompatible,
  offers HuggingFace Hub browse as escape hatch
- Persistent config saved to ~/.config/meshnet/config.json (0o600)
- Live rich dashboard (tokens/sec EMA, VRAM, requests, peers, uptime) with
  automatic plain-text fallback when stdout is not a TTY (WSL2/SSH/CI)
- All wizard values overridable via CLI flags; --reset-config re-runs wizard
- `meshnet-node models` lists curated models; `--browse` fetches HF Hub top-20
- `meshnet-node config` prints saved config
- `meshnet-node start ...` preserved for backward compatibility
- 19 new tests; 97 passed, 1 skipped (no regressions)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 17:45:38 +03:00
Dobromir Popov
65dee3d6d1 feat: tracker-as-first-layer-node inference entry point (US-014)
Tracker: GET /v1/tracker-nodes/<model> returns head-shard nodes registered
with tracker_mode=true. tracker_mode stored per node in registry.

Node (stub + torch): head nodes (shard_start==0 or --tracker-mode flag)
expose /v1/chat/completions alongside /forward. Pipeline: tokenize →
embed → own layers → GET /v1/route (skip self) → binary forward through
remaining hops → decode → SSE back to client.

Gateway: proxies round-robin to tracker-nodes when found, falls back to
existing direct pipeline when none registered. All US-005 tests still pass.

CLI: --tracker-mode and --tracker-url flags on meshnet-node start.

Tests: 4 new integration tests — valid responses on 10 requests, both
tracker-nodes receive load, exact 5/5 round-robin split. 78 pass, 1 skipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 17:00:52 +03:00
Dobromir Popov
dbf856f497 feat: tracker-as-first-layer-node inference entry point (US-014)
- Tracker: add GET /v1/tracker-nodes/<model> returning nodes registered
  with tracker_mode=true whose shard_start matches the model's first layer
- Node: StubNodeServer and TorchNodeServer accept tracker_mode/tracker_url;
  when tracker_mode=True (or auto-detected via shard_start==0 for Torch),
  /v1/chat/completions is served alongside /forward
- TorchNodeServer: full pipeline implementation — encode_prompt → route
  selection via tracker → binary forward through remaining hops → decode
- Gateway: _handle_chat_completions checks _get_tracker_nodes() first and
  proxies round-robin to tracker-nodes; falls back to existing direct
  pipeline when none found (preserves all US-005 backward compat)
- CLI: --tracker-mode and --tracker-url flags added to meshnet-node start
- Test: two stub tracker-nodes + two mid-shard nodes for gpt2; 10 requests;
  round-robin 5/5 split verified; all OpenAI-format responses validated
- All 78 tests pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:59:32 +03:00
Dobromir Popov
753f553766 feat: coverage-first tracker shard assignment (US-013)
Recovered from interrupted Codex session (ended 13:02, changes uncommitted).
All 74 tests pass.

- Tracker accepts vram_bytes, ram_bytes, quantizations[], benchmark_tokens_per_sec
  in node registration payload
- GET /v1/coverage/<model_preset> returns [{start_layer, end_layer, node_count}]
- Coverage-first bin-packing: fills gaps before adding redundancy
- Speed-weighted assignment: faster nodes get wider shard ranges
- LOAD_SHARD/DROP_SHARD rebalance directives delivered via heartbeat responses
- Model is unroutable when any layer range has node_count=0
- model_presets.json config for bytes_per_layer at each quantization level

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:37:48 +03:00
Dobromir Popov
85c13e4e82 feat: add per-story metadata line to Ralph dashboard
Each story shows an optional second line with agent · worktree · summary:
- _active_worktrees(): parses git worktree list --porcelain, maps feat/<id> branches
- _story_meta(): joins agent name, worktree path, completionNotes/last commit subject
- print_dashboard: renders metadata line indented below story title
- --compact flag on show/watch suppresses metadata for tight one-line-per-story view

Also wires worktree-by-default groundwork: _active_worktrees called once per
render, worktree paths shown relative to repo root.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:32:35 +03:00
Dobromir Popov
0152d5ed99 feat(us-015): Ralph status-aware dashboard, agent-agnostic runner
Part 1 — status-field awareness:
- _is_done/_needs_attention/_is_active/_is_in_design helpers with passes fallback
- _story_sets returns 6-tuple: done/attention/active/in_design/ready/blocked
- Dashboard shows ⚠ Attention Required section with status_reason
- auto skips to-revise/needs-review; --include-revise overrides
- _review_report includes Attention Required section

Part 2 — agent-agnostic runner:
- --agent codex|claude|openrouter|custom on run-next/auto/review
- set-agent subcommand persists choice to .ralph-tui/agent-config.json
- _run_openrouter stub (needs OPENROUTER_API_KEY)
- _run_custom_agent: --agent-cmd script receives prompt file as $1
- list-parallel: shows ready stories safe to run concurrently

Part 3 (parallel opt-in): auto --parallel N flag available but not default

Missing (follow-up patch): worktree-by-default for single runs,
per-story metadata line in dashboard (_active_worktrees/_story_meta)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:30:22 +03:00
Dobromir Popov
7bd663d9b8 feat: Ralph status-aware dashboard, agent-agnostic runner, worktree parallelism
- Add _is_done/_needs_attention/_is_active/_is_in_design status helpers with
  passes-field backward compatibility for old prd.json files
- Rewrite _story_sets to return 6 buckets: done, attention, active, in_design,
  ready, blocked
- Dashboard shows ⚠ Attention required section with status_reason for
  to-revise/needs-review stories; progress bar counts attention as complete
- _review_report includes dedicated Attention Required section
- auto skips attention stories by default; --include-revise flag overrides
- _status_symbol updated to handle all status values (⚠ ?  ✎ • →)
- Agent-agnostic runner: --agent codex|claude|openrouter|custom on run-next,
  auto, review; default agent loaded from .ralph-tui/agent-config.json
- set-agent subcommand writes agent-config.json (agent + optional model)
- _run_openrouter stub with clear error when OPENROUTER_API_KEY not set
- Custom agent support: --agent custom --agent-cmd ./script.sh runs script
  with prompt file as $1
- list-parallel subcommand prints ready stories with no shared dep chain
- auto --parallel N creates git worktrees, runs N agents concurrently,
  merges on success, preserves on failure for manual resolution
- Mark US-015 done in prd.json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:27:41 +03:00
Dobromir Popov
8ea70ff6a0 docs(us-015): add Part 4 — per-story agent/worktree/summary in dashboard
Each story shows an optional second line:
  agent · status · worktree path (if not main) · last output summary

Sources: git worktree list, agent-config.json, session.json,
completionNotes, git log on feat/<id> branch, iteration logs.
--compact flag suppresses metadata lines.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:21:57 +03:00
Dobromir Popov
dac81a66b4 chore(prd): expand US-015 scope with worktree parallelism
auto --parallel N: creates one worktree per ready task, runs N agents
concurrently, merges on success, preserves worktree on conflict.
list-parallel: shows stories safe to run concurrently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:14:33 +03:00
Dobromir Popov
d3bb50a894 feat(prd): add US-015 — Ralph agent-agnostic runner + status-field dashboard
Status-field awareness:
- Replace passes:bool with status field in ralph_progress.py
- Six buckets: done, attention, active, in-design, ready, blocked
- Dashboard shows ⚠ Attention Required section for to-revise/needs-review
- auto skips attention stories by default; --include-revise overrides

Agent agnosticism:
- --agent codex|claude|openrouter|custom on all run commands
- Persistent config in .ralph-tui/agent-config.json via set-agent subcommand
- OpenRouter adapter: calls API directly when ralph-tui lacks native plugin
- custom: --agent-cmd <script> receives prompt file as $1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:10:28 +03:00
Dobromir Popov
bf5055e6e0 chore(prd): replace passes boolean with rich status field
Status vocabulary: open | in-design | in-progress | needs-review | to-revise | done | blocked
Vocabulary definition stored in metadata.statusVocabulary for tooling.

US-002 → to-revise (base64 wire format replaced by binary in US-011)
US-005 → to-revise (gateway orchestration role superseded by US-014 tracker-as-node)
US-014 → open
All others → done

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:07:48 +03:00
Dobromir Popov
2690d9b9ba feat: add real PyTorch model backend 2026-06-29 15:54:40 +03:00
Dobromir Popov
c358798627 chore: harden Ralph session controls 2026-06-29 15:54:00 +03:00
Dobromir Popov
8895e5e8f1 chore: add Ralph session controls 2026-06-29 15:36:47 +03:00
Dobromir Popov
cd9e3686a5 docs(adr-0002): lock TAI tokenomics — 1B supply, revenue-backed, 90% floor
Locked decisions:
- 1 billion TAI hard cap, no minting, halving-style emission decay
- No transfer tax; spread-only revenue, decreases with volume
- Buyback floor = 90% of current organic backing price (ratcheting up)
- Wind-down guarantee: 90% floor always funded by protocol spread
- Post-listing speculative risk acknowledged and accepted
- Node bootstrap: probationary period = stake-free entry (no loan/grant)
- Listing threshold (provisional): $50k volume AND 25 nodes / 15+ operators

Open parameters noted: halving schedule, dynamic spread curve, listing %, legal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:34:15 +03:00
Dobromir Popov
202b579bd1 docs(adr-0002): rewrite TAI tokenomics with revenue-backed model
- Token named TAI, fixed supply (BTC-inspired), no open market during bootstrap
- Price anchored to inference revenue: team holds ~100% → 36% over ~5 years
- 95% soft buyback floor; ~10% protocol spread funds wind-down reserve
- Wind-down guarantee: protocol can always buy back all issued TAI at issue price
- Open questions section captures unresolved parameters for token launch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:15:15 +03:00
Dobromir Popov
2a4383e353 feat: add binary activation wire format 2026-06-29 14:58:55 +03:00
Dobromir Popov
b17deb4d0e chore: add Ralph progress dashboard 2026-06-29 14:58:19 +03:00
Dobromir Popov
b02e07d308 docs: add ADRs and user stories for real model inference stack (US-011–014)
ADR-0008: binary activation wire format — raw bfloat16 over HTTP, zstd compression,
128-token chunked prefill; replaces base64 JSON (~33% overhead removed).

ADR-0009: coverage-first shard assignment and tracker-as-first-layer-node —
any node serving layers[0..k] becomes the inference entry point for that model;
bin-packing fills all coverage gaps before adding redundancy; tracker issues
LOAD_SHARD/DROP_SHARD rebalance directives; nodes declare VRAM + quantization.

US-011: binary wire format migration
US-012: real PyTorch layer execution (transformers + bitsandbytes, test on GPT-2)
US-013: coverage-first tracker bin-packing with VRAM-aware shard assignment
US-014: tracker-as-node (tracker node serves first layers + handles client requests)

CONTEXT.md: Tracker Node, Coverage Map, Rebalance Directive terms added.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 14:43:54 +03:00
Dobromir Popov
3286f77e27 feat: add meshnet python sdk 2026-06-29 10:29:19 +03:00