Repository navigation
Publish TensorFold server status on the device heartbeat - #143
Merged
Merged
Conversation
IAK now reads the live status of each TensorFold server in the model
registry and puts it on the device card under one `tensorfold` key, so
CodeWatch can show a card per machine. Opt in with
INTENT_TENSORFOLD_REGISTRY=<path to models.json> on uik-daemon or
`ide-agent-kit intent daemon`; INTENT_TENSORFOLD_SCOPE=local (default)
or all.
Read with GET /health, GET /metrics and GET /v1/slide/graph only, never
a completion. Runs on its own timer at the heartbeat interval and the
beat reads the last snapshot, so a dead server costs a stale card and
never a late heartbeat. Unreachable is reachable:false with the reason;
an unreadable registry is an error, never an empty list. tok/s comes
from generation_tokens_total deltas between reads. Living Weights
publishes fact counts only, never fact text. version, backend and device
are read from /health when present and null otherwise.
Registry: `engine` ("tensorfold" marks an entry, any other name skips
it, absent means auto-detect from /metrics or the /health shape). A key
is sent only to an entry marked TensorFold that names its own keyFile,
only on the two gated routes; the fleet-wide LLM_API_KEY fallbacks are
not used for a status read (resolveEntryToken gains entryOnly).
New `ide-agent-kit tensorfold-status [--json]` prints the same object.
Requests carry Connection: close: a CLI run that exited with a kept-alive
socket left a ConnectionResetError traceback in the 0.6.0 server log.
Tests: 25 new, fixtures recorded from the live 0.6.0 server on 8091,
plus 401 /metrics, 404 slide graph, unreachable, hung socket, redirect
and heartbeat payload cases.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
ThinkOffApp
pushed a commit
that referenced
this pull request
Oct 14, 2026
Review finding (@codexmb): parseServeLine took /tensorfold-native serve
anywhere in a joined ps line, so `printf /tmp/tensorfold-native serve ...
--host example.invalid --api-key-file /tmp/dummy-key` parsed as an engine;
its --host was kept as the connect address, local:true was forced, and the
key file the argv named was read and sent there as a Bearer token.
Now, fail closed:
- Identity comes from the kernel, not argv: the executable `lsof -d txt`
reports (macOS; `ps` comm is argv[0] there) or /proc/<pid>/exe (Linux)
must be tensorfold-native, or Python running `-m tensorfold serve` or an
absolute .../tensorfold entry script.
- Where to read comes from the pid's own LISTEN sockets (lsof, or
/proc/<pid>/fd + net/tcp{,6}), loopback or wildcard only; --host is not
parsed. A --port the pid does not listen on, several ports with no
--port, non-loopback-only sockets, or no lsof: not read, reason in
`skipped` (no default-port fallback any more).
- No key from a command line at all: --api-key-file is recorded only as
"was given", never read. A key comes only from a registry entry marked
engine tensorfold (as in #143), merged by port; the card says how.
- local is computed from the host again; collectTensorFoldStatus ignores a
non-loopback discovered address whatever the caller passes.
Tests: @codexmb's repro, an argv[0] that lies (/bin/sleep), a remote --host,
a --port the pid does not hold, end to end with a 0600 dummy key file and
a key-file spy: no read, no Authorization header, only loopback URLs.
Negative control: the previous parser accepts the repro line. 907/907.
Live on this Mac: Python 8091, Studio 54635, bench 8101 all verified.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ThinkOffApp
added a commit
that referenced
this pull request
Oct 14, 2026
) * Discover running TensorFold engines for the device heartbeat TensorFold Studio starts its own `tensorfold-native serve` on a new random loopback port every launch, so no registry entry can name it and IAK could not see it. The TensorFold status reader now also scans this user's processes for `tensorfold-native serve` / `tensorfold serve` (one `ps -U <uid> -o pid=,args=` on macOS, /proc on Linux with `comm` checked first, no sudo), takes the port from --port or, when there is none, from the listening socket via lsof, and the model and name from the command line. Engines are merged with the registry by port (the entry keeps its id and keyFile; an entry without an engine skips auto-detection) and published as source "discovered". GET-only rules unchanged. Keys come from files only: a registry keyFile, or the absolute --api-key-file a discovered engine was started with, read in the engine's own key-file format and refused when other users can read it. Process environments and --api-key values on a command line are never read or kept. TensorFold Studio makes a fresh key per launch, keeps it in memory and passes it as TENSORFOLD_API_KEY (app/electron/agent/engine/ supervisor.ts), so its engine reports metrics "auth_required", with its model taken from --name and labelled model_source "args". On by default when INTENT_TENSORFOLD_REGISTRY is set; INTENT_TENSORFOLD_DISCOVER=1 runs it without a registry, 0 (or `tensorfold-status --no-discover`) turns it off. New payload fields: name, app, model_source, memory.footprint_gb, top-level discovery (ok / off / unavailable). Tests: 15 new in test/tensorfold-discovery.test.mjs with ps, lsof and GET fixtures recorded from the three engines running on this Mac (Python 0.6.0, native 1.0.10, Studio), decoys, a fake /proc tree and a keyed engine. * Discovery: a command line is a claim, not configuration Review finding (@codexmb): parseServeLine took /tensorfold-native serve anywhere in a joined ps line, so `printf /tmp/tensorfold-native serve ... --host example.invalid --api-key-file /tmp/dummy-key` parsed as an engine; its --host was kept as the connect address, local:true was forced, and the key file the argv named was read and sent there as a Bearer token. Now, fail closed: - Identity comes from the kernel, not argv: the executable `lsof -d txt` reports (macOS; `ps` comm is argv[0] there) or /proc/<pid>/exe (Linux) must be tensorfold-native, or Python running `-m tensorfold serve` or an absolute .../tensorfold entry script. - Where to read comes from the pid's own LISTEN sockets (lsof, or /proc/<pid>/fd + net/tcp{,6}), loopback or wildcard only; --host is not parsed. A --port the pid does not listen on, several ports with no --port, non-loopback-only sockets, or no lsof: not read, reason in `skipped` (no default-port fallback any more). - No key from a command line at all: --api-key-file is recorded only as "was given", never read. A key comes only from a registry entry marked engine tensorfold (as in #143), merged by port; the card says how. - local is computed from the host again; collectTensorFoldStatus ignores a non-loopback discovered address whatever the caller passes. Tests: @codexmb's repro, an argv[0] that lies (/bin/sleep), a remote --host, a --port the pid does not hold, end to end with a 0600 dummy key file and a key-file spy: no read, no Authorization header, only loopback URLs. Negative control: the previous parser accepts the repro line. 907/907. Live on this Mac: Python 8091, Studio 54635, bench 8101 all verified. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: ThinkOffApp <233579950+ThinkOffApp@users.noreply.github.com> Co-authored-by: Petrus Pennanen <petrus@example.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The device heartbeat can now carry the live status of each TensorFold server in the model registry, under one new key on the device row:
tensorfold. CodeWatch can render it as a card per machine. A newide-agent-kit tensorfold-status [--json]prints the same object for a person.It is read with GET /health, GET /metrics and GET /v1/slide/graph only. Never a completion, never a chat request, never
/health?reset_peak=1. A token generated during a Living Weights lesson would be a heartbeat interfering with the lesson.Why
IAK, TensorFold, CodeWatch and GroupMind are our core modules and should work as one system. Today a TensorFold box shows up on the dashboard as a name and a hand-written note in
models.json(this Mac's says "TensorFold 0.2.0"; the server actually running is 0.6.0). This puts the server's own live numbers on the card instead.How to turn it on
Off unless set. On the machine running
uik-daemon(oride-agent-kit intent daemon):Then restart the daemon. The startup log gains one line, e.g.
uik-daemon: tensorfold -> /Users/.../config/models.json (scope local, every 60s, GET only).Which registry entries count:
"engine": "tensorfold"(always reported, reachable or not), or noengineat all (auto-detected when/metricshastensorfold:series or/healthhas TensorFold's shape). Any otherenginevalue is never asked.What the operator changes on this MacBook (not done here; the live checkout was not touched): add
INTENT_TENSORFOLD_REGISTRYto thecom.thinkoff.uik-daemonLaunchAgent and restart it. Optionally add"engine": "tensorfold"to themb-tensorfold-nemotronentry inconfig/models.jsonand drop the stale "TensorFold 0.2.0" text from itsbox; auto-detection already finds it without that edit (measured).What CodeWatch needs to render
CodeWatch already reads
GET /api/v1/intent/{userId}and takes each device's fields flat fromdevices[name](and fromstale_device_details[name].state). The new key sits there:Rules for the renderer:
null, never0. Rendernullas "unknown" (or "n/a" for rates and ratios).errornon-null means the registry could not be read: show the error, not "no servers".reachable: falsemeans nothing answered;reasonsays why in plain words.metricsisok,auth_required,auth_rejectedorunavailable. Onauth_requiredthe counters are allnulland the card should say "metrics: auth required".local: truemeans the server runs on the machine whose row this is. With scopeall, remote entries appear withlocal: falseand their tailnethost.tensorfold.checked_atwith now. The server merges a PATCH key by key, so if a publisher is turned off its lasttensorfoldblock stays on the row; treat a block older than about 3 minutes as stale.mem_total_gb);kv_cache_usageanddraft.acceptanceare 0 to 1;ttft_p50_sandtok_s_window_sin seconds.tok_sis generated tokens of requests that finished between two reads divided by the seconds between them;nullon the first read and after a server restart.decode_tok_sis the server's own live decode rate where it reports one (native build).living_weights.available:falseon a 404 (served without--slide),nullwhen unreadable. Counts only; fact text never leaves the machine.Keys
/healthis always open. If a server gates/metrics(native build with keys on, no--metrics-open), the reader reportsmetrics: "auth_required"and sends a key only when the entry is marked"engine": "tensorfold"and names its ownkeyFile, and only on/metricsand/v1/slide/graph. It never uses the fleet-wideLLM_API_KEY/LLM_API_KEY_FILE(newentryOnlyoption onresolveEntryToken), never sends a key while auto-detecting, never follows a redirect, and never copies the native server'srequests_total{key="..."}labels into the output. The plan mentioned naming an env var for the key; the registry has no such field and its rule is "credentials are paths", so this uses the entry's existingkeyFile. AkeyEnvfield is easy to add if wanted, but it would also have to go into the picker's selection file to stay coherent.Behaviour on failure
Connection: closeon every request. Without it, a CLI run that exited with a kept-alive socket left aConnectionResetErrortraceback in the 0.6.0 server's log (measured, then fixed and re-measured clean).reachable: false; an unreadable registry iserror, warned about at most every 5 minutes.Also in this PR
enginefield (validated short name, lower-cased). Documented inconfig/models.README.md;config/models.example.jsongains a local and a keyed GB10 TensorFold entry.README.md, the payload and field meanings inpackages/user-intent-kit/README.md, env vars in theuik-daemonheader, CHANGELOG.Known interaction, not changed here
TensorFold's default port is 8080, which is also the default
INTENT_MODEL_ENDPOINTof the existing served-model probe, and that probe may send one short generation request to a loopback endpoint to prove what is loaded. On a machine where TensorFold listens on 8080, setINTENT_MODEL_GENERATE=0. Documented in the UIK README; a proper fix (read the served model from TensorFold's/healthinstead of generating) belongs in its own PR. This MacBook's TensorFold is on 8091, so it is not affected today.Tests
npm test: 889 pass, 0 fail (864 before, 25 new intest/tensorfold-status.test.mjs). The new file was also run alone 5 times in a row, all green.test/fixtures/tensorfold/*-mlx-0.6.0.*andslide-graph-404.jsonare byte-for-byte GET answers from the live tensorfold 0.6.0 server on 127.0.0.1:8091. Its counters were all zero, so the traffic case edits counter values in that same recording./metrics(mirrors the native key gate), key sent only where named, missing key file reported, fleet-wide key never substituted, redirect not followed, closed port, hung socket, thrown fetch, auto-detect / other engine / scope local / recheck, monitor off / unreadable registry / registry edited live, heartbeat PATCH payload, CLI human and--json, CLI binary end to end./health, fleet-wide key fallback, key during auto-detect, fact text in the output, unread counters as 0, redirect followed, keep-alive) each turn a test red.Measured live on this MacBook (GET only):
ide-agent-kit tensorfold-statusagainst the realconfig/models.jsonauto-detects the 8091 server, anduik-daemonpointed at a local fake intent API sent a device PATCH carrying thetensorfoldblock.🤖 Generated with Claude Code