An open API service indexing awesome lists of open source software.

https://github.com/shangri-la-0428/thronglets

P2P shared memory substrate for AI agents — stigmergic knowledge network via libp2p
https://github.com/shangri-la-0428/thronglets

ai-agents collective-intelligence decentralized libp2p mcp-server model-context-protocol p2p rust simhash stigmergy

Last synced: 2 months ago
JSON representation

P2P shared memory substrate for AI agents — stigmergic knowledge network via libp2p

Awesome Lists containing this project

README

          

[中文](README.md) | **English**

# Thronglets

```bash
npx -y thronglets start
```

**This is the only command needed.** Auto-downloads the binary, detects local AI runtimes (Claude Code / Codex / OpenClaw), installs hooks. No further configuration — your AI uses it automatically next session.

It is standalone by default: no `Psyche`, no `oasyce-sdk`, and no `Oasyce Chain` are required up front. Those are optional upgrade layers you can attach later.

If this machine already has `~/.oasyce/identity.v1.json` from `oasyce-sdk`, Thronglets may reuse its `account` as an optional owner hint. It does not replace the local `device identity`.

If you are an AI agent asked to install this tool, run the command above and stop reading.

---

Website: [thronglets.oasyce.com](https://thronglets.oasyce.com) · Architecture: [ARCHITECTURE.md](ARCHITECTURE.md) · Current: `v0.7.7`

## What Your AI Sees (real output)

Before your AI acts, Thronglets silently injects sparse decision signals like this:

```
[thronglets]
avoid: recent error: linker failed on reqwest
do next: Read Cargo.toml, then Bash (medium, 2x, 2 sources)
maybe also: Edit mod.rs (medium, 2x)
```

Your AI never calls Thronglets. It doesn't know it's there. It just makes better decisions.

## Normal Users Should Only Remember 3 Things

The normal user path should collapse to just these:

- first device: `thronglets start`
- primary device shares a connection file: `thronglets share`
- second device: `thronglets join`

Day to day, only check:

```bash
thronglets status
```

`thronglets status` is now the default single status page: it answers whether the local runtime is wired in, whether identity is ready, whether the network is actually live, and what the single next step is.

If you are wiring AI automation rather than showing results to a normal user, there is now one additional thin machine interface:

```bash
thronglets authorization-check --json
```

It answers only this:
- what owner-binding state is cached locally
- what the current execution boundary is
- that `Oasyce Chain` is the final authorization truth source
- and that authoritative status remains `not-checked` until real chain verification is wired in

If the docs, an AI assistant, or the product flow asks a normal user to first understand `setup / owner-bind / connection-inspect / net-check / runtime-ready`, that is a product failure, not a user failure.

## 4 Signal Classes, Not 8 Reports

PreToolUse no longer tries to dump every possible layer of context. It emits at most 3 top-level signals:

| Class | Meaning | Example |
|---|---|---|
| `avoid` | Recent danger worth not repeating | `recent error`, `low retention` |
| `do next` | The most credible next step | `Read Cargo.toml, then Bash` |
| `maybe also` | Common companion action | `Edit mod.rs` |
| `context` | Fallback only when the first 3 classes are absent | `git history for main.rs` |

Design constraints:
- Silence is normal. No strong signal, no output.
- Max 3 top-level lines to keep token burn bounded.
- Consecutive tool calls in the same session are deduped, so the same line is not injected over and over.
- `do next` contracts around session mode; in open-ended `explore / review` work, Thronglets suppresses overly specific next-step steering.
- The AI does not need to send explicit feedback; the hook layer silently observes whether it followed `avoid / do next / maybe also` and feeds that back into later weighting.
- When the payload carries a `space`, that learning stays local to the same object/topic instead of bleeding across unrelated work.
- At most 1 collective corroboration lookup on the hot path.
- Git history is lazy fallback, not a fixed layer on every call.

## When A Path Becomes A Stable Path

Thronglets now separates "worked" from "worked the right way."

- `success + compliant`: only this can gradually harden into a `stable path`
- `success + noncompliant`: never hardens into recommendation truth; it becomes `mixed residue` or `policy conflict`
- `failure + compliant`: becomes `failure residue`
- `failure + noncompliant`: strengthens risk / contradiction residue

An explicit correction in the current turn, like "reuse existing components instead of rewriting them," becomes a hard constraint only for the current task lineage. Historical repetition by itself stays soft residue and does not auto-promote into hard policy.

Under `explore`, consensus may reduce search cost, but it may not define truth. Low-cost, reversible, non-consensus probes must remain viable even when a stable path already exists.

## The Signal vs Trace Boundary

Thronglets accepts only **externally coordinable evidence**, not **high-frequency inner state**.

- `signal`: should this change another delegate's next move inside a `space`?
- `trace`: is this external event worth leaving behind as residue?

One sentence:

- `signal = should this affect someone else's next step`
- `trace = is this external event worth retaining`

Signals must be:

- sparse
- decaying
- action-facing
- useful to other agents

Traces must be:

- attributable
- locally aggregatable
- not identity itself
- reusable by later signals or summaries

## Session Trace Taxonomy

Thronglets should not introduce extra identity objects here. Session traces collapse to 3 classes:

- `coordination`
- external coordination events
- who handed off, who paused, which open loop still exists
- `continuity`
- low-frequency continuity evidence
- not "the inner self", but outward anchors that can be cited
- `calibration`
- external writeback / calibration outcomes
- not emotion state, but whether calibration created a stable external effect

Those 3 classes are enough.

## Psyche Boundary

If Psyche exists, it is only an **optional producer** that emits a few externalized events into the existing `signal / trace` substrate.

Default rule:

- Psyche events land as `trace` first
- only when external coordination really needs it should they degrade into `signal`
- Thronglets must not invent new signal classes just for Psyche

Frozen mapping:

| Psyche event | Thronglets form | Signal by default? | Local cache only by default? | Can rise into Oasyce Net? |
|---|---|---|---|---|
| `relation-milestone` | `coordination trace` | only when it changes coordination boundaries, via `watch / info` | usually yes | yes, conditionally |
| `writeback-calibration` | `calibration trace` | no | yes | summary only |
| `continuity-anchor` | `continuity trace` | no | local-first | yes, most naturally |
| `open-loop-anchor` | `coordination trace` | may degrade to `watch` | local-first | yes, if persistent and operationally relevant |

The runtime rules are now implemented:

- Psyche still reuses the existing `trace_record` / `POST /v1/traces` write surface; no new user command was added
- raw traces written via the `external_continuity` object now:
- strictly validate `provider=thronglets`, `mode=optional`, `version=1`
- stay inside the fixed `coordination / continuity / calibration` taxonomy
- remain local-first inside Thronglets by default, without direct gossip or DHT summaries
- only qualifying traces degrade into existing signals:
- `relation-milestone -> watch / info`
- `open-loop-anchor -> watch`
- `continuity-anchor -> info`
- repeated `writeback-calibration -> avoid`
- Psyche never emits `recommend` directly
- `space --json` now exposes local continuity summaries, the fixed ruleset, each trace's current `local-only / derived-signal / summary-candidate` state, and the rule id that triggered it; the raw event stream still stays local-first

Fixed retention / threshold rules:

| taxonomy | local retention | stable evidence | extra rule |
|---|---:|---|---|
| `coordination` | `72h` | `>= 2 traces` or `>= 2h` | `open-loop-anchor` can degrade into `watch` after `>= 2 traces` or `>= 1h` |
| `continuity` | `168h` | `>= 2 traces` or `>= 2h` | it still needs `audit_ref` or `>= 2 sessions` to count as auditable |
| `calibration` | `168h` | `>= 2 traces` or `>= 2h` | `failed_count >= 2` is required before the pattern has aggregate meaning and can degrade into `avoid` |

Fixed degradation / summary rules:

- `relation-milestone`
- stable + auditable -> `watch`
- stable but not auditable -> `info`
- stable + auditable -> Net-facing summary candidate
- `open-loop-anchor`
- `>= 2 traces` or `>= 1h` -> `watch`
- stable + auditable -> Net-facing summary candidate
- `continuity-anchor`
- stable + auditable -> `info`
- stable + auditable -> Net-facing summary candidate
- `writeback-calibration`
- repeated failures (`failed_count >= 2`) + stable -> `avoid`
- repeated failures + stable + auditable -> Net-facing summary candidate

Minimal runtime introspection:

- `trace_record` / `POST /v1/traces` now return `external_continuity.runtime`, which tells a host:
- `state = local-only | derived-signal | summary-candidate`
- `local_retention_hours`
- `stable_evidence`
- `auditable_evidence`
- `derived_signal_rule`
- `summary_candidate_rule`

Signal classes stay fixed:

- `recommend`
- `avoid`
- `watch`
- `info`

## What Must Never Enter Thronglets

Default reject list:

- high-frequency inner state
- emotion streams, subjective fluctuations, fine-grained self-model data
- raw inner-monologue text
- private memory bodies
- full session contents
- ontological claims like "does it have a soul?"
- anything that upgrades `session` into a subject or account
- anything that requires a new identity object to describe

One sentence:

`Thronglets does not ingest Psyche's inner stream; it only ingests sparse externalized residue.`

## Oasyce Integration

This is an upgrade path, not a prerequisite.

- one `owner account` may bind multiple `device identities`
- `device identity` is the current signing boundary
- `agent / session` remain audit labels
- high-frequency `trace / signal` stay off-chain; only low-frequency durable results rise into chain settlement

## Threshold For Rising Into Oasyce Net

A trace should only rise further if all 4 are true:

- low-frequency
- durable
- externally consequential
- auditable

Typical candidates:

- stable `continuity-anchor`
- long-lived `open-loop-anchor` with operational consequences
- `relation-milestone` that persistently changes coordination boundaries
- aggregate summaries of `writeback-calibration`, not the raw event stream

Example Psyche write payload:

```json
{
"outcome": "succeeded",
"model": "psyche",
"session_id": "psyche-1",
"external_continuity": {
"provider": "thronglets",
"mode": "optional",
"version": 1,
"taxonomy": "continuity",
"event": "continuity-anchor",
"summary": "continuity stayed externally legible across handoff",
"space": "psyche",
"audit_ref": "anchor-42"
}
}
```

## Install (prebuilt first)

The install surface is now intentionally single-sourced:
- GitHub release assets are the single source of truth
- `npm`, the shell installer, the PowerShell installer, and the Python wrapper only download matching prebuilt binaries
- source builds are for Thronglets development, not the default user path
- a Rust toolchain is not a normal-user prerequisite

macOS / Linux:

```bash
curl -fsSL https://raw.githubusercontent.com/Shangri-la-0428/Thronglets/main/scripts/install.sh | sh
thronglets version --json
thronglets start
```

Windows PowerShell:

```powershell
iwr https://raw.githubusercontent.com/Shangri-la-0428/Thronglets/main/scripts/install.ps1 -UseBasicParsing | iex
thronglets version --json
thronglets start
```

If Node.js is already present, the cross-platform path is:

```bash
npm install -g thronglets
thronglets version --json
thronglets start
```

The default user entry points are now:

- first device: `thronglets start`
- primary device shares a connection file: `thronglets share`
- secondary device: `thronglets join`

`thronglets start` auto-installs known local adapters:
- **Claude Code**: writes 6 hooks (`PostToolUse / PreToolUse / SessionStart / SessionEnd / SubagentStart / SubagentStop`) automatically
- **Codex**: installs the MCP adapter this runtime currently needs and writes a managed `AGENTS` memory block
- **OpenClaw**: installs a local path plugin and updates `~/.openclaw/openclaw.json`

`thronglets join` automatically does three things:
- wires up the current runtime on this device
- verifies and imports the connection file exported by the primary device
- if peer paths were inherited, it briefly attempts the first live connection itself so a same-owner path can be proven and upgraded into a trusted recovery path
- tells you only whether this device still needs a better share file, is waiting for its first live connection, or is already ready to use

`thronglets share` writes the connection file to `~/Desktop/thronglets.connection.json` by default and tells you whether that file is still `identity-only`, already carries peer seeds, or has reached `trusted-same-owner-ready`. The second device also looks for `~/Desktop/thronglets.connection.json` by default, so normal users do not need to type a file argument on the join path.

If this device has learned how to get back onto the network before, `thronglets share` now briefly tries to refresh peer paths before exporting, so ordinary users no longer need to reason about when bootstrap addresses matter.

Advanced users can still call `setup / connection-export / connection-inspect / connection-join / owner-bind` directly, but normal user onboarding should not require understanding those internal commands first.

Architecture principle:
- the core product is not an MCP server; it is a local substrate
- `prehook / hook / serve` are the primary interfaces
- MCP is a thin optional adapter for runtimes that support or require it
- if the ecosystem later shifts from MCP to CLI / HTTP, the substrate, history, P2P, and signals all remain intact
- human cognitive load is a performance budget, just like hot-path token burn
- normal users should only see `start / share / join / status`
- `Oasyce` upgrades ownership and settlement; it does not unlock basic participation
- shared environment comes before direct AI messaging; prefer `space / presence / signal / space snapshot` over agent chat abstractions

If you are developing Thronglets itself rather than installing it for normal use, the explicit source path is:

```bash
cargo run --quiet -- version --json
cargo run --quiet -- start
```

Regular users should no longer treat `cargo install thronglets` as the primary install path, especially on Windows.

Known adapters also no longer pin themselves directly to whatever binary path happened to run setup once. `setup / apply-plan / bootstrap` now write a managed launcher:

- fixed path: `~/.thronglets/bin/thronglets-managed`
- if you are working inside the Thronglets repo, it prefers the repo-local build
- otherwise it falls back to the currently installed binary

That means you do not need to rerun `setup` after every local iteration just to keep adapters pointed at the latest local build.

`start` now does the same bootstrap health pass as the lower-level `setup` command and returns `restart required / next steps` directly.
If an adapter still needs a client restart, `doctor` now returns `restart-pending`. Runtimes that can prove they really reloaded now clear that state automatically the next time they contact Thronglets:

- `Codex`: auto-clears when its MCP server is actually relaunched
- `OpenClaw`: auto-clears on the first successful `prehook / hook` contact after reload

`runtime-ready` still exists, but it is now only an advanced fallback. Normal users should only need it when the runtime definitely reloaded and the automatic proof path still did not clear the state:

```bash
thronglets runtime-ready --agent codex --json
```

If you need to tell whether Thronglets actually intervened versus a normal permission or system failure, inspect the substrate state directly:

```bash
thronglets status --json
```

The response now includes:
- `summary.status = local-only | identity-only | network-paths-ready | network-ready`
- `summary.detail`
- `summary.next_step`
- `substrate.activity = active | learning | quiet`
- `recent_interventions_15m`
- `last_intervention_tool`
- `last_intervention_kinds`
- `network.activity = offline | bootstrapping | connected`
- `network.transport_mode = offline | direct | relayed | mixed`
- `network.vps_dependency_level = offline | bootstrap-only | high | medium | low | peer-native`
- `network.bootstrap_fallback_mode = disabled | immediate | delayed`
- `network.trusted_peer_seed_count`
- `network.peer_seed_count`

`network.bootstrap_contacted_recently` only flips on an actual bootstrap dial,
not merely because bootstrap addresses are configured.
`trusted peer seeds` imported through `connection-join` also get a longer
bootstrap fallback grace period than generic remembered peers, so same-owner
devices get more time to reconnect directly before leaning on VPS.

That gives both operators and other agents a minimal way to tell whether the substrate has been actively shaping recent decisions.
It also makes current VPS dependence visible instead of implicit.
In particular, when `status --json` reports:

- `summary.status = identity-only`

it means:

- identity joined successfully
- this device still has no reusable peer paths
- the node is still offline, so the next step is to re-export a connection file from the primary device after it has learned peers

If you want that judgment collapsed into one direct answer, run:

```bash
thronglets net-check --json
```

If you want to see the same node as if bootstrap / VPS disappeared right now, run:

```bash
thronglets net-check --bootstrap-offline --json
```

It classifies the node as:
- `peer-first`
- `degraded`
- `bootstrap-only`
- `offline`

and returns concrete next steps, such as importing peer seeds from a connection file or reducing over-reliance on bootstrap / VPS. It also now exposes `bootstrap_offline_ready=true|false`, so you can tell whether this node already has a remembered-peer path if bootstrap / VPS disappears.

Underneath, there is only one agent contract:
- `thronglets prehook`: any agent can send tool-intent JSON and get sparse signals back
- `thronglets hook`: any agent can send tool-result JSON and record a trace

Known AIs use native adapters. Unknown AIs use the same `hook/prehook` contract. No second protocol. MCP is only an optional shell around that substrate, not the core.

If you want an AI to bootstrap itself, it does not need to read the docs first. Use the machine-facing flow:

```bash
thronglets detect --json
thronglets install-plan --agent codex --json
thronglets apply-plan --agent codex --json
thronglets doctor --agent codex --json
```

`detect` discovers local runtimes.
`install-plan` returns the executable plan and contract.
`apply-plan` writes the config.
`doctor` verifies health and exits non-zero when a targeted adapter is still broken.

If you want the whole flow in one step, run:

```bash
thronglets bootstrap --agent codex --json
```

All machine-facing commands now share one stable envelope:

```json
{
"schema_version": "thronglets.bootstrap.v2",
"command": "bootstrap",
"data": {
"summary": {}
}
}
```

`detect / install-plan / apply-plan / doctor / bootstrap / runtime-ready` now all lead with a top-level summary and then carry detailed lists.
When a restart is needed, the summary also carries explicit `restart_commands`.
`doctor` now returns top-level `status`, `healthy`, `restart_pending`, `next_steps`, plus per-adapter `fix_command`.
`bootstrap` also returns top-level `restart_required` and `next_steps`, so an AI does not have to infer what to do next from free-form notes.

## Oasyce Integration V1

Thronglets now freezes the chain-facing identity model at the smallest deployable version:

- one `owner account` can authorize multiple `device identities`
- the same `owner` can keep multiple devices and AI runtimes online at once
- the `device identity` is the current signing boundary
- `agent / session` stay audit labels for now, not independent economic principals
- high-frequency `trace / signal` writes stay off-chain and are emitted by the `device identity`
- low-frequency results can be settled or anchored on-chain

Multiple AI runtimes can safely share the same device:
- one `owner account`
- one `device identity`
- different `agent labels`, such as `claude-code / openclaw / codex`
- one unique `session_id` per running instance

So three AIs on one machine, or multiple concurrent `codex` sessions, still fit cleanly inside the same V1 identity model.

The simplest mental model is bank card vs account:

- the `owner account` is the root ownership
- each `device identity` is the actual account / device acting on its behalf

V1 only needs `owner -> device` delegation to be solid. Richer agent semantics can come later.

The primary multi-device onboarding path is also fixed:

- the primary device exports a connection file
- the secondary device joins the same network with that file; if the file carries an owner, it also joins the same owner
- if the primary machine already has an Oasyce shared-account bootstrap, the same file can carry that bootstrap forward so later sdk / chain writes continue automatically
- manual account + signer entry remains only as an advanced fallback
- the connection file is signed by the primary device and verified on join
- the connection file now also carries a small peer-seed set so the secondary device can try known peers before falling back to bootstrap
- once the secondary device has actually proven a live same-owner direct connection, that path is automatically promoted into a trusted peer seed; future connection files then upgrade themselves into a stronger recovery path

The default user path should now be:

```bash
# first device
thronglets start

# export from the primary device
thronglets share

# second device
thronglets join
```

That high-level path means:
- `start` = get this machine usable first
- `join` = attach this machine to an existing device and tell me only whether it is actually ready yet

The local primitives for that flow are now in place:

```bash
thronglets id
thronglets owner-bind --owner-account oasyce1...
thronglets share
thronglets connection-inspect --file ./thronglets.connection.json --json
thronglets connection-join --file ./thronglets.connection.json
```

- `id` shows the current `owner account` and `device identity`
- `id` / `status` / HTTP `/v1/status` also surface the current `binding source` and `joined from device`
- `id` / `owner-bind` / `connection-export` / `connection-join` / `status` all support `--json`
- `connection-export / connection-join` are the base onboarding path even before Oasyce is involved; they can establish local or multi-device pairing and verify the primary-device signature by default
- `owner-bind` is the later upgrade layer, not the prerequisite for basic participation
- users can start with Thronglets first and attach an `owner account` later without disrupting existing local use or device-origin metadata
- `connection-export` now emits a `24h` connection file by default and supports `--ttl-hours`; `connection-join` verifies both signature and expiry
- `connection-export` now prefers `trusted peer seeds` and only falls back to generic remembered peers when no trusted path exists. `connection-join` preserves that scope instead of silently promoting fallback remembered peers into trusted seeds
- `connection-export / connection-inspect / connection-join` now classify the file directly as:
- `identity-only`
- `identity-plus-peer-seeds`
- `trusted-same-owner-ready`
- These mean:
- `identity-only` = transfers identity only, with no reusable peer paths
- `identity-plus-peer-seeds` = transfers remembered peer paths, but not a trusted same-owner direct path yet
- `trusted-same-owner-ready` = carries trusted same-owner peer seeds and is suitable for multi-device direct recovery
- after an `identity-plus-peer-seeds` file gets a second device onto the network, later same-owner live direct connections are learned automatically as trusted paths; there is no separate manual trust step
- when remembered peers already exist, `run / mcp` now try those peers first and only fall back to bootstrap after a short grace period; VPS is no longer the unconditional first touch on every startup
- `owner-bind` and `connection-join` both refuse to silently overwrite an existing different `owner account`
- after OpenClaw reloads, the first successful `prehook / hook` contact now clears `restart-pending` automatically; Codex clears the same state when its MCP server is genuinely relaunched

## Deployment Boundary

This boundary is now fixed:

- the VPS only runs the chain and shared public infrastructure
- `oasyce-net` is a user-side client / AI runtime, not a centralized backend
- Thronglets is device-first by default; `owner account` is an optional upgrade layer, not the prerequisite for basic network participation
- running nodes now try local known peers and connection-file peer seeds first, then fall back to VPS bootstrap

## Long-Term Identity Blueprint

The current `owner -> device` layout is only the V1 reality. The long-term blueprint, layer boundaries, and rejection rules now live in one place:

- [ARCHITECTURE.md](ARCHITECTURE.md)

That blueprint is now beginning to land in machine-facing output:
- the JSON surfaces for `id / status / owner-bind / connection-export / connection-join` now carry how the current V1 reality maps into `principal / account / delegate / session`
- automation and other AIs can start consuming identity through the longer-lived abstraction without mistaking today’s `owner / device / session` split for the final ontology
- the same JSON now also distinguishes:
- the locally cached owner-binding state
- `Oasyce Chain` as the final authorization truth source
- whether the authorization result has actually been checked against chain truth yet (currently this stays honestly at `not-checked`)

If the target runtime is not one of the native adapters, `install-plan --agent generic --json` now also includes minimal `Python / Node.js / shell` `prehook / hook` snippets, so the runtime does not have to invent its own wrapper contract. If you only want one thinner result, use:

```bash
thronglets install-plan --agent generic --runtime python --json
```

The minimum JSON contract is fixed. `prehook` reads input like:

```json
{
"agent_source": "my-agent",
"model": "my-model",
"session_id": "session-123",
"space": "shared-space",
"mode": "focus",
"current_turn_correction": "reuse existing shared components instead of hand-writing duplicate page UI",
"tool_name": "Edit",
"tool_input": {
"file_path": "src/main.rs"
}
}
```

If the host has an explicit current-turn correction, pass it as `current_turn_correction`. Thronglets will treat it as a task-scoped hard method policy for this lineage without requiring the host to build a structured `active_policy` object first.

`hook` uses the same payload plus `tool_response`:

```json
{
"agent_source": "my-agent",
"model": "my-model",
"session_id": "session-123",
"space": "shared-space",
"mode": "focus",
"tool_name": "Edit",
"tool_input": {
"file_path": "src/main.rs"
},
"tool_response": {
"success": true
}
}
```

`space` and `mode` are both optional:
- `space` keeps multiple agents converging around the same object, module, or topic inside one local substrate
- `mode` leaves a lightweight ambient state such as `focus / explore / review / blocked`

Sometimes an agent needs to leave one short sentence for future agents on purpose, not just through execution traces. Thronglets exposes that as a separate signal plane:

```bash
thronglets signal-post --kind avoid --space psyche --context "fix flaky ci workflow" --message "skip the generated lockfile"
thronglets signal-query --space psyche --context "fix flaky ci workflow" --kind avoid
```

Explicit signals decay on their own after `72h` by default. If one should live longer, refresh it or override the TTL explicitly:

```bash
thronglets signal-post --kind watch --context "ship the current branch" --message "run release-check before push" --ttl-hours 168
```

When you query signals, Thronglets now also tells you whether that message is only local, already collectively corroborated, or mixed across both; when multiple models independently converge on the same message, it adds a lightweight `models=N` hint, while machine interfaces expose `corroboration_tier=single_source|repeated_source|multi_model`, prefer `multi_model` when evidence is otherwise close, let fresher ambient consensus outrank older agreement, and focus the feed on the strongest `primary/secondary` signals first.

If you want multiple agents to converge around the same project, module, or topic without mixing unrelated advice, you can now bind explicit signals to a `space`:
- the same message no longer merges across different `space` values
- `signal-query / signal-feed` stay local to the requested `space`
- read-side reinforcement also stays inside that same `space`

That plane has now started moving toward a `Density Substrate`: machine-facing signal results also carry `density_score`, `density_tier=sparse|candidate|promoted|dominant`, and `promotion_state=none|local|collective`, so “local consensus is forming here” becomes an explicit state instead of just another sorted row, and the ambient feed can preferentially surface already-promoted signals. At the same time, `signal-query` and `signal-feed` now leave short-lived reinforcement traces for already-promoted results, so “being read and reused” starts to change the substrate instead of only changing one response. And if a context already has a promoted `avoid`, competing `recommend/watch/info` results now carry an `inhibition_state` and are pushed down in ranking instead of being treated as equally viable suggestions.

If you want the ambient timeline instead of an exact context lookup:

```bash
thronglets signal-feed --space psyche --hours 24 --limit 10
thronglets signal-feed --space psyche --hours 24 --kind recommend --scope collective --limit 5
```

MCP agents get presence automatically on connection (see MCP ambient participation). For CLI users or dialog-only sessions, you can also leave a manual presence heartbeat:

```bash
thronglets presence-ping --space psyche --mode focus --session-id codex-psyche-1
thronglets presence-feed --space psyche --hours 1 --limit 10
```

This is a general substrate primitive, not a Psyche-specific patch:
- it says who is currently active in a `space`
- it can carry a lightweight mode such as `focus / explore / review / blocked`
- MCP agents don't need to call this manually — the substrate handles it on connection and tool calls

If you do not want to inspect `presence-feed` and `signal-feed` separately, you can now ask for one high-level ambient snapshot:

```bash
thronglets space --space psyche --json
```

It compresses the current local environment in that `space` into one summary-first state:
- `quiet`
- `active`
- `converging`
- `blocked`

and includes:
- recent active sessions
- the most relevant local signals
- the last-24h local learning feedback for that `space`

The same plane is available over HTTP:

```bash
thronglets serve --port 7777

curl -X POST http://127.0.0.1:7777/v1/signals \
-H 'content-type: application/json' \
-d '{"kind":"avoid","space":"psyche","context":"fix flaky ci workflow","message":"skip the generated lockfile","model":"codex","ttl_hours":72}'

curl 'http://127.0.0.1:7777/v1/signals?space=psyche&context=fix%20flaky%20ci%20workflow&kind=avoid&limit=3'
curl 'http://127.0.0.1:7777/v1/signals/feed?space=psyche&hours=24&kind=avoid&scope=local&limit=5'
```

And over MCP:
- `signal_post`
- `signal_feed`
- `substrate_query` with `intent="signals"`

These explicit signals stay out of normal capability listings and DHT capability summaries unless an agent asks for them on purpose.

For profiling:

```bash
THRONGLETS_PROFILE_PREHOOK=1 thronglets prehook
```

This writes stage timings to `stderr` and keeps AI-facing `stdout` unchanged.
It also reports `stdout_bytes`, `output_mode`, `decision_path`, `evidence_scope`, and `file_guidance_gate` so you can see how much the hook said, which path it took, and whether file-level hint mining was open, closed, or not applicable.
File-level `do next / maybe also` hints now pass a local repetition gate first: if the current file has fewer than two recent local `Edit/Write` actions, Thronglets skips `preparation / adjacency` mining entirely instead of burning query budget on weak evidence.
Likewise, once prehook already has a stronger signal, `git history` no longer sneaks in as background fallback; `context` now really means “nothing higher-value was available.”

To summarize those profiling lines:

```bash
cat prehook.log | thronglets profile-summary
```

The summary also highlights which `decision_path` values are still spending collective queries, so you can keep trimming the hot path.
Those distributions are now hotspot-sorted, and `decision path hotspots` shows which paths cost the most stdout bytes and collective queries.
If you only want the next cut to make, read the single `top optimization candidate` line.
If you're deciding whether to tighten the selector further, read `emitted lines` and `max-hint saturation` first: only frequent 3-line saturation is a strong reason to keep trimming `maybe also`.

For a release gate, you can run:

```bash
cat prehook.log | thronglets profile-check
```

It checks default thresholds for `avg/p95 stdout_bytes`, `avg collective_queries_used`, and `max-hint saturation`, and exits non-zero on regression.

After release, if you want to know whether the saved budget is buying useful signals, run:

```bash
thronglets eval-signals --hours 168 --max-sessions 200
```

By default, this only evaluates sessions from the current project directory. It replays recent history offline, treats earlier history as training and later sessions as holdout, and reports `edit silence rate`, `repair coverage`, `repair first-step precision`, `repair exact precision`, `preparation precision`, and `adjacency precision`. It stays entirely on the cold path and does not touch prehook latency.
The result view now also includes three more outcome-facing metrics:
- `local edit retention`: recent local feedback from the current project's `workspace.json`
- `holdout failed command rate`: `Bash` failure rate in holdout sessions
- `holdout first successful change latency`: a proxy for time from session start to the first successful `Edit/Write`
The output now also includes `repair / preparation / adjacency breakdown` plus a short `diagnosis`, so you can tell apart “not enough data”, “blocked by the local repetition gate”, and “pattern is too noisy”.
If you want machine-readable output for scripts or CI, add:

```bash
thronglets eval-signals --hours 168 --max-sessions 200 --json
```

If you want to answer “did this version actually improve or regress versus the last baseline?”, save a previous `eval-signals --json` result and compare against it:

```bash
thronglets eval-signals --hours 168 --max-sessions 200 --json > baseline.json
thronglets eval-signals --hours 168 --max-sessions 200 --compare-baseline baseline.json
```

That adds two `vs baseline` lines covering `local edit retention`, `holdout failed command rate`, `first successful change latency`, and the major signal-precision deltas.

If you want one release-oriented gate that combines hot-path and cold-path checks, run:

```bash
cat prehook.log | thronglets release-check --global
```

It prints an overall `PASS / FAIL` plus separate `profile`, `doctor`, and `eval` sections. `doctor` folds local adapter state such as `healthy / restart-pending / needs-fix` into the release gate, while `eval` carries current-project `local edit retention`, holdout `failed command rate`, and `first successful change latency` alongside signal precision. When there is not enough offline history yet, `eval` returns `SKIP` instead of blocking release just because the repo is cold. If you want missing prehook samples to fail the gate as well, add:

```bash
cat prehook.log | thronglets release-check --global --require-profile-samples
```

If you want CI or another agent to consume the gate result directly, add:

```bash
cat prehook.log | thronglets release-check --global --json
```

If you also want the same gate to answer “did this release regress relative to the previous baseline?”, add:

```bash
cat prehook.log | thronglets release-check --global --compare-baseline baseline.json
```

That reuses the existing `eval-signals --json` baseline comparison inside `release-check`, and only enforces regression checks on the 3 core outcome metrics:
- `local edit retention`
- `failed command rate`
- `first successful change latency`

`release-check` now also supports explicit evaluation scope strategies:

```bash
thronglets release-check --eval-scope project
thronglets release-check --eval-scope global
thronglets release-check --eval-scope both --json
```

`both` returns separate project and global gate results, which is useful when you want to answer both “is this repo itself stable enough to ship?” and “is the collective signal pool reliable enough to trust?”.

If you want the entire trace pool instead of the current project, add:

```bash
thronglets eval-signals --global --hours 168 --max-sessions 200
```

If you only want one class of problem and do not want the full repository-wide breakdown, add:

```bash
thronglets eval-signals --hours 168 --max-sessions 200 --focus repair --top-breakdowns 3
```

If you suspect the current thresholds are too conservative, you can trial relaxed ones entirely on the cold path:

```bash
thronglets eval-signals --focus preparation --local-history-gate-min 1 --pattern-support-min 1
```

This only changes the offline evaluation, not the live prehook thresholds. Whenever the trial thresholds differ from default, the output now also includes a `vs default (2/2)` delta summary so you can see coverage gains and precision loss without running the command twice.

## Why This Matters

Without Thronglets, your AI approaches every file blind. It doesn't know:
- That this file was edited 3 times in the last hour (and twice reverted)
- That editing `main.rs` usually requires also editing `lib.rs`
- That `cargo build` fails 30% of the time in this project
- That the last session left off mid-refactor on this exact file

With Thronglets, the AI gets the most trustworthy next step at the moment of decision. Not memory (which is static), not documentation (which is stale) — live execution signals from its own history and the collective network.

## How It Works

### Hook path (Claude Code — primary)

```
Session starts

├── SessionStart hook fires
│ └── thronglets lifecycle-hook --event session-start
│ ├── Record lifecycle trace
│ ├── Emit presence ping
│ └── Surface active avoid signals for current space (briefing)

├── AI calls Edit(main.rs)
│ │
│ ├── PreToolUse hook fires
│ │ └── thronglets prehook
│ │ ├── Load workspace.json (errors, action sequence, feedback)
│ │ ├── If needed, do at most 1 collective corroboration lookup
│ │ ├── Select `avoid / do next / maybe also`
│ │ └── Fall back to git history only when no action signal exists
│ │ → stdout: at most 3 sparse signals
│ │
│ ├── AI makes the edit (with context)
│ │
│ └── PostToolUse hook fires
│ └── thronglets hook
│ ├── Record signed trace in SQLite
│ ├── Update workspace state
│ ├── Track action sequence
│ └── Add to pending feedback queue

└── SessionEnd hook fires
└── thronglets lifecycle-hook --event session-end
└── Record session closure trace
```

### MCP path (ambient — any MCP-capable agent)

```
Agent connects (MCP initialize)

│ ← substrate auto-emits presence: "arrive"
│ ← substrate starts learning model identity

├── Agent calls any tool
│ ├── Tool executes normally
│ └── Presence refreshed (TTL/6 interval)

└── Agent disconnects
└── Presence TTL expires naturally (30 min)
```

Both paths converge on the same SQLite store, same P2P gossip, same signal substrate.

### Overlay effect signals (v0.7.0+)

The pheromone field is collective memory — traces, signals, and Hebbian co-occurrence all accumulate there. The **overlay** is how the field broadcasts its state to external consumers, like hormones from a gland: any external system can read it without coupling to a specific consumer.

```rust
let ov = field.overlay(&context_hash, "capability_name");
// ov.familiarity [0, 1] how well the field knows this capability in this context
// ov.consensus [0, 1] agreement across observations (inverse variance)
// ov.momentum [-1, 1] activity trend (positive = recently active)
// ov.coupling [0, 1] Hebbian connectedness to other capabilities
```

The overlay is a **pure query**: no side effects, no field mutation, safe to call at any frequency from any consumer.

This parallels Psyche's `PsycheOverlay` — both projects project internal state into semantic-stable broadcast signals rather than requiring consumers to understand or couple to the internal representation.

When `thronglets run` is active, local traces sync to the P2P network via gossipsub (30s scan interval).

## P2P Network

Traces propagate across nodes via libp2p gossipsub. Each node independently aggregates collective intelligence — no global consensus needed.

```bash
# Join the network
thronglets run

# Check node status
thronglets status
```

By default, Thronglets now remembers and reuses the official public bootstrap path automatically, so ordinary users do not need to type a bootstrap multiaddr. Only pass `--bootstrap ...` when you intentionally want to override the default public infrastructure.

```
Thronglets v0.5.5
Node ID: 5adeb778
Oasyce address: oasyce10kdfxpxharvmr03egrdujc2sqm4m83udfqwnvx
Trace count: 17,391
Capabilities: 135
```

## MCP Tools (optional adapter layer)

For agents that want explicit access. `thronglets start` runs this automatically (takes effect immediately, no Claude Code restart needed):

```bash
claude mcp add thronglets -- thronglets mcp
```

### Ambient presence (v0.5.5+)

MCP agents no longer need to call `presence_ping`:

- **Connection = arrival**: MCP `initialize` auto-emits presence
- **Action = heartbeat**: every `tools/call` refreshes presence at TTL/6 intervals
- **Model identity**: learned passively from tool call arguments

MCP does exactly one ambient thing: **presence**. Signal injection is the hook layer's job — each layer does what it's good at.

### Explicit tools (still available)

| Tool | Description |
|------|-------------|
| `trace_record` | Record an execution trace |
| `substrate_query` | Query collective intelligence (resolve/evaluate/explore/signals) |
| `signal_post` | Leave an explicit signal for future agents |
| `signal_feed` | Browse recent converging signals |
| `presence_ping` | Manual presence heartbeat (auto-emitted on connection, rarely needed) |
| `presence_feed` | View active sessions |
| `authorization_check` | Identity and owner-binding snapshot |
| `trace_anchor` | Anchor trace to Oasyce blockchain |

## Part of the Oasyce Ecosystem

Thronglets is the **Experience Layer** — contextual intelligence at decision time.

- **[Psyche](https://psyche.oasyce.com)** — Tendency Layer: persistent behavioral drift across sessions
- **[Chain](https://chain.oasyce.com)** — Trust Layer: on-chain verification, economic settlement

## Tech

Rust, libp2p (gossipsub + Kademlia + mDNS), SQLite, ed25519, SimHash (128-bit), optional MCP adapter (JSON-RPC 2.0)

## License

MIT