Releases: Neguiolidas/Conscio
Release list
v4.8.2 — The Promptor refines, and zcode sees the update
Three changes ship together: the Experts squad's Promptor stops grading
prompts and starts rewriting them, the plugin's marketplace entry finally
carries a version so the zcode auto-update can see new releases (it had
been stuck on 4.7.3), and a relay message to a peer that cannot be reached
is parked and reported as parked instead of as delivered.
Changed — the Promptor is a prompt refiner (no longer a vote)
The Experts squad's promptor voice no longer evaluates prompts and no
longer votes. It rewrites: it receives a prompt and returns a
refined_prompt (the input restructured into Objective / Context /
Constraints / Output format sections) plus a short changes list. Every
substantive line is verbatim from the input; anything missing becomes an
explicit [UNSPECIFIED — …] marker inside the refined prompt — the
refiner never invents a fact and emits no verdict.
- Mechanism: voices carry a
votingflag (defaulttrue). The
Promptor setsvoting = false, soconvene_squadexcludes it from
recommendationandvotes_summarywhile its payload still rides in
voiceswith an emptyvote— choosing a per-voice flag over a
hardcoded name keeps the aggregation generic for future non-voting
voices. - LLM path (
use_llm=true): the attached adapter rewrites the
prompt; on any LLM failure the deterministic refinement is returned
unchanged. The refiner never raises into a squad convene. - Minimal fragments, not whole sections: when a constraint or a
format is named inside a larger clause, the refined prompt quotes only
the fragment that carries it (from the keyword, or the preposition
right before it, to the end of the clause) — it no longer repeats the
whole question or the whole context under every heading. - Limits are constraints: "max 300 words", "under $5 per month", "at
most 3 bullets", "limited to two pages", "máx. 200 palavras" land in
Constraints. Ambiguous words (under,up to,most,limited, …)
count only next to a number, so "explain it under the hood" is not a
limit; currency, abbreviations (max.,min.) and accented
Portuguese forms are recognised. - Keywords match whole words: "notable"/"stable" no longer light
table, "commonly" no longer lightsonly. - English first: detection is tuned for English input and the
section labels and gap markers are always English. Portuguese keywords
are additive and chosen never to collide with English words, so
English prompts cannot regress because of them. - Consumers updated:
conscio_squad_expertsschema description,
engine.squad_expertsdocstring, the MCP guide's Experts table, the
index page, and the tests pinning the old evaluate-and-vote behavior.
Fixed
- zcode never offered a plugin update after 4.7.3. zcode decides
whether a plugin has an update by comparing the installed version with
the marketplace entry's own"version"field, and reports "no update"
when that field is missing — theconscioentry had none, so the
catalog refreshed on every scan while the installed plugin stayed on
4.7.3. The entry now carries the version, and
tests/test_marketplace_version.pykeeps four copies in lockstep: the
marketplace entry, the shippedplugin.json, the.mcp.jsonuvx pin
andconscio.__version__.docs/RELEASING.mdstep 1 lists all four. - A message to an unreachable peer was reported as sent. A remote
peer's bridge that refused the connection or timed out gave the same
answer as one that rejected the message, andconscio_relay send
returnedokfor a message that only sat in this host's spool.
The transport now tells ACCEPTED, REJECTED and UNREACHABLE apart. A
bridge that answers "no" still fails the send; a peer that does not
answer gets the message parked in this host's spool for it to pull,
andsendreturns awarningnaming the peer and the URL that did not
answer.broadcastcarries the same warning on that peer'ssent
entry — before, the fan-out listed only an id, which reads as "it
arrived".
v4.8.1 — Awake stops paying to confirm that nothing happened
A field run of Awake Mode drained its provider quota: the maintenance goal
re-proposed host_health on every heartbeat (~300 LLM calls/day to re-confirm
"all normal", measured on the field ledger), a 429 storm cascaded through every
gateway tier, and the ledger recorded the failures with an empty error. This
patch caps the call volume, makes the gateway stop on rate limits, and fixes the
smaller defects the same report and the follow-up audit surfaced. No schema
change: the ledger gains no column, so existing databases open unchanged.
Fixed — Awake Mode call volume (conscio/awake/calibration.py)
- Maintenance cooldown. The
daemon_checkmaintenance goal expires after
its act and is regenerated only afterMAINTENANCE_COOLDOWN_MIN = 60minutes,
read from the action ledger (the last attempt for that goal fingerprint), so
the cooldown survives daemon restarts. The reflect cycle still runs on every
heartbeat; only the LLM-backed act is gated. - One maintenance cycle per heartbeat. When the maintenance goal is the only
active goal, the loop runs it once and stops (stopped: "maintenance_cycle_cap")
instead of repeating it for the wholemax_cyclesbudget. A failed attempt
still counts as the one cycle; a heartbeat that also holds another goal is
never capped. - Rolling 24h attempt ceiling.
DAILY_LLM_CEILING = 120act attempts by the
autonomous loop per rolling 24h window (tier != 'host', so host-approved
acts never consume it). Failed attempts count whatever their token count: a
429 storm writestokens = 0rows and still burns quota. When the ceiling
trips, awake degrades to perceive + reflect, emits the trip on the event bus,
and the heartbeat'slast_run.stoppedreadsdaily_cost_ceiling. - No active goals is IDLE, not a failure. A heartbeat with no executable goal
returnsActStatus.IDLE(stopped: "idle"); it no longer feeds the failure-rate brake, which
used to stop a healthy idle daemon after a few heartbeats. The IDLE break runs
after dream housekeeping, so an idle daemon still prunes its ledgers.
Fixed — Gateway failure handling (conscio/agency/)
- Typed HTTP status. HTTP errors from inference backends raise
AdapterHTTPError(a subclass ofAdapterBadResponse) carryingstatus.
FailureGovernor.classifymaps 429 →RATE_LIMIT, 401/403 →PERMANENT,
5xx →PROVIDER_OUTAGE, any other status →MALFORMED_STREAM. - Fast-fail on rate limit and outage. On
RATE_LIMITorPROVIDER_OUTAGE
the gateway stops instead of falling back to a lower tier: every tier calls
the same provider, so the fallback only repeated the 429.TIMEOUTstill
falls through (local grammar decoding can be slow and T3 may succeed). - Failure reason in the ledger. Failed act rows persist the reason in the
existingerrorcolumn (gateway: …,decode failed: …) instead of''. - Tool-name normalization. A proposed tool name is stripped of whitespace,
wrapping quotes/backticks and a trailing()before lookup (host_health()
resolves tohost_health); no lowercasing and no fuzzy matching. - Instructions without value slots. The JSON and key-value format
instructions describe each field in prose instead of a"<tool name>"
placeholder the model echoed back verbatim; tool names are listed sorted, and
the dead instruction constants were removed.
Fixed — Recall and council
conscio_recall_observationssession scope. The defaultscope="session"
filtered on the MCP server's own session id, which no capture hook ever
writes, so it silently matched nothing. It now resolves the session in order:
an explicitsession_id(exposed in the tool schema), the session the
platform wired into the engine, the most recent session recorded for the
project (the current repository by default) and, when noprojectwas
given, the most recent session among observations recorded without one. If
none exists it answersINVALID_PARAMSsaying so. The project path is
canonicalized (~expanded and, when the path exists, resolved to the
enclosing repository root) so a subdirectory or a tilde path matches the
stored project.- Council trait negation. A post-trigger absence predicate ("backups are
missing") is consumed by the trigger it negates and can no longer also act as
a pre-trigger negator for a later trigger in the same sentence.
Security and hygiene
- Bandit HIGH findings: 3 → 0. The two non-security
sha1digests (short
ids inintegrations/neurata.pyandoutcomes.py) pass
usedforsecurity=False; the relay reactor'sshell=Truecall
runs the operator's own notify pipeline with the payload on stdin, never
interpolated, and carries a# nosec B602annotation that says so. - Dead code removed.
OutputGatewayloses the unused_failure_gov
attribute andfailure_governorparameter, and the vulture whitelist entry
that hid them. - Internal plans out of the repo and the site. The v4.5 relay-halls
implementation plans (docs/plans/) are no longer tracked or published on
the docs site;.gitignoreand mkdocsexclude_docsnow cover them, along
with local per-agent harness files. uv.lockback in sync. The lockfile was missing thebuilddev
dependency thatpyproject.tomlhas declared since v4.0.0, so
uv lock --checkfailed on a clean checkout.
v4.8.0 — The space survives, the machine has a board, the council can be measured
This release decouples agent storage from disposable plugin paths into durable,
host-bound spaces (~/.conscio/instances/<slug>), introduces a machine-level
ambient task board swept by the relay reactor, and delivers a calibration harness
with an opt-in typed decision judge for the four-voice council.
Added — Durable space (v4.8 S1)
Decouples agent state from disposable plugin directories (which are wiped on
updates) by binding spaces per host identity under ~/.conscio/instances/<slug>.
Existing plugin-bound spaces remain untouched until migrated; fresh installations
mint into durable space directly.
- Pure space resolver (
conscio/installer/durable.py).resolve_space(storage, env)
classifies the environment across states B0–B6 and migration locks without
side effects (repair_pointer=Truesignals the caller to create or update the
pointer):- B0 (Legacy): unmigrated plugin space; prints stderr announcement to run
conscio space migrateand uses the legacy path byte-for-byte. - B1 (Bound): valid
space-pointer.jsonpointing to an existing durable
target; follows the pointer. - B2 (Adopted): plugin directory wiped without local identity, but durable
space exists; adopts the durable space (repair_pointer=True) and warns to
re-arm the relay reactor ifmigrated-from.jsontombstone is present. - B3 (Conflict / Divergence): two copies found (plugin and durable);
refuses boot with a message distinguishing identical IDs (copies may have
diverged) from distinct IDs (identity conflict). - B4 (Residual evidence): previous identity evidence found (tombstone or
local relay card) but no live space exists; refuses boot without minting
silently. Fails closed with an explicit error if the relay directory cannot
be read. - B5 (Dangling pointer): pointer exists but target is missing; refuses
boot. - B6 (Fresh mint): neither space nor evidence exists; mints into durable
space under exclusive flock withrepair_pointer=True.
- B0 (Legacy): unmigrated plugin space; prints stderr announcement to run
- Pointer minting with exclusive flock (
conscio/installer/spaces.py).
Concurrent boots serialize via an exclusiveflockon
~/.conscio/instances/.minting-<slug>(5 s timeout) with a mandatory re-read of
instance.jsonupon acquisition to prevent ID divergence. Degrades safely with
a warning on filesystems without full lock support (ENOLCK/EOPNOTSUPP). - Refusal markers (
space-refused.json). Whentarget is None
(B3/B4/B5/lock), the server writes an atomicspace-refused.jsonmarker in the
plugin data directory and exits 2 without touching storage or minting. Cleared
automatically upon successful resolution or migration. - Stdlib hooks cascade ("when in doubt, do not write"). Pure stdlib hooks
(deepminer,obsstore,honesty,wake) run in isolated processes and
evaluate files locally: pointer → migration lock → refusal marker → legacy B0
→ silent exit 0. Hooks never block agent turns. - Atomic migration command (
conscio space migrate). Migrates legacy
plugin-bound spaces to durable instances via 8 strict atomic steps:- acquire
.migrating-<slug>lock; - create timestamped backup in
~/.conscio/backups/pre-migrate-*(keeps 2
generations); - move content of
space/while preserving the folder; - write
migrated-from.jsontombstone in durable root; - atomically write
space-pointer.jsonin plugin directory; - remove
space-refused.json; - release migration lock;
- print regenerated systemd user unit definitions for the durable path.
Protected by two pre-flight gates: process-zero (inspects/proc/*/cmdline,
checking launcher names and open file descriptors to safely exempt parent
shells while blocking active legacy processes) and quiet-minutes (verifies no
file modifications within--quiet-minutes). Supports idempotent item-by-item
resumption with tree and file equality checks.
- acquire
- Space checks in
relay doctor(D1–D5). Read-only
diagnostics:- D1: lists orphan spaces in
instances/(ignoring hidden dotfiles and lock
files). - D2: flags downgrade ghosts and suggests
conscio relay forget. - D3: identifies orphan
migrated-from.jsontombstones. - D4: reports deferred migrations with active process PIDs.
- D5: detects stale migration locks with dead PIDs and suggests resuming via
conscio space migrate --slug <slug>(never deletes automatically). - Lists active
space-refused.jsonrefusal markers with state and age.
- D1: lists orphan spaces in
Added — Council calibration (v4.8)
A calibration round for the four-voice council: an opt-in judge, trait-
sharpened deterministic votes, a readiness gate, and an offline
benchmark. The voices' contract — they never call an LLM or an
attached adapter — is intact; the votes now also read a 9-trait
extraction of the question text, and the new result fields are
additive.
- Optional council judge (
conscio/judge.py). One canonical
decision question, answered by your typed decision API through the
shareddecision_adaptertransport (config: an emptyjudge
marker block plus adecision_adapterblock — seeUSAGE.md). The
judge is off unless configured, and no env var alone turns it on.
Any failure is a status string, never an exception:ok,off,
no_key,bad_config,no_adapter,timeout,network,
http_<code>,malformed,internal_error— the last two mark the
judge boundary: a response that fails validation, or an unexpected
error, is logged and the council falls back to deterministic mode.
Only the council'squestion,
contextand, when present,optionsleave the machine. - Trait-sharpened deterministic votes. All four voices stay
deterministic (the pinned contract: they never call an adapter) and
now also read a 9-trait extraction of the question text (English
only — see the limitation inUSAGE.md). The per-voice weight
table inconscio/gates.pyis commented with the dev round that
produced each value. - Readiness gate. A
proceedonly leaves the council when the
engine is ready — not inaction_lockdown, not in a critical
metabolic state, and, when a coherence score exists, coherence ≥
0.5. Not ready ⇒ lowered tohold, reasons ingate_reason; the
gate never promotes. New additive result fields:mode,
judge_status,gate_reason, and thejudgereport in judged
mode. - Calibration bench + relabel tool. An offline harness
(tests/test_council_calibration.py+tests/council_bench.py)
measures agreement with the frozen judge labels — Cohen's kappa
plus a confusion matrix, per origin — on a 114-case corpus
(61 dev + 53 heldout, hash-pinned in
tests/fixtures/council_bench/MANIFEST.json). Tuning never reads
the heldout half; only the harness and the relabel tool open it.
scripts/council_bench_relabel.py
re-labels the heldout against a live judge and reports drift
without writing to the fixture. The harness prints its headline
literally as agreement with the judge labels, not ground-truth
correctness. - Docs. The optional judge, its config keys, statuses, result
fields, the gate, and the English-only limitation are documented in
USAGE.md(root and packaged copies); theconscio_councilentry
indocs/guides/mcp.mdnow mentions the judge.
Added — Ambient: one task board per machine (v4.8 S3)
One task board per relay root (<relay_root>/ambient/board.db, SQLite/WAL,
user_version=1, busy_timeout=5000), swept by the relay reactor's own tick —
no new daemon. All four surfaces resolve the same board (invariant I1): the
conscio_board MCP tool, the conscio ambient CLI, the ambient node, and the
doctor.
conscio_boardMCP tool +conscio ambientCLI. The board's write
surface:task {propose,create,assign,list,show,claim,renew,submit,review, release,block,cancel},orchestrate {acquire,renew,release},status,
report,doctor, andwake <id> --dry-run. The MCP tool is a single
conscio_boarddispatch; the actor is always the server's own identity —
there is noas=argument.- The ambient node rides the reactor tick. While enabled it notices
assigned work over the relay (atask_dispatchcarrying only the task id),
re-notifies a stalled reviewer on a cap, and — through the connector gate —
may wake a non-live agent. A brokenconscio.ambientpackage costs the node
and never a relay delivery. - Off by default. Without the
<relay_root>/ambient/enabledflag file the
node gives its sweep back and touches nothing (conscio ambient enable
creates it). The board and CLI keep working while disabled. board.proposetravels over the relay. The one board write a remote
machine may perform: a peer asks for work and it lands as aproposedtask
withcreator = senderandorigin = <message id>(a redelivery dedupes on
origin). It is a reserved type the generic relay refuses; only
conscio_board op=propose to=<peer>sends it.- Wake registry with a zero default budget.
<relay_root>/ambient/agents.json
names the connectors a machine may use; every agent'swake_budget_per_day
defaults to 0, so nobody is woken until the owner opts them in. - The
claude-bgconnector. The one connector in this release. A wake
runsclaude --bg [--model M] <prompt>inside its own
systemd-run --user --scope, so the session outlives a reactor restart; its
output goes to temporary files, stdin is/dev/null, and the call times out
after 60 s. The session id is read from thebackgrounded · <id>line. A
spawn that exits 0 with an id is a success; otherwise a429/rate-limit
message is recorded asrate_limitedand anything else asspawn_error.
Liveness readsclaude agents --json:workingis live;done,failedor
a session missing from the list is not;blocked, an unrecognised state, a
non-zero exit or output t...
v4.7.3 — The doctor asks the process, not the disk
Found by the post-update test of 4.7.2 (2026-09-24): 4 of the 7
restart warnings from relay doctor were false, the answer changed with the
directory the doctor ran from, and a reactor running code from 09-22 was not
listed at all.
Fixed
relay doctorasks the interpreter the process actually runs. The
version probe used/proc/<pid>/exe, the symlink-resolved base interpreter,
which does not see the venv (uv tool, uvx archive,.venv). It now invokes
cmdline[0](resolved on the process's ownPATH) and reproduces that
process'ssys.path[0],PYTHON*env and-I/-Pflags. The doctor's own
PYTHONPATHand cwd no longer leak into the answer.- The dist-info fallback stops at the process's own install. For a Python
executable, the parent directories are the base interpreter's install
(under uv they reached~/.localand an unrelated dist-info), so only path
arguments are walked now. This also covers an interpreter replaced on
disk ((deleted)). Editable dist-infos are skipped: theirVersionis
the install-time one, not the loaded code (measured: 4.7.1 and 3.8.2 for
processes loading 4.7.2). - A wrapper process is no longer judged by the disk. When the interpreter
answered that conscio is not importable there (a watchdog or launcher, not
Conscio), the doctor now skips the process — a reachable dist-info can no
longer resurrect it as stale.
Added
relay doctorflags a process older than its code on disk. An
in-place upgrade or an editable repo after a bump leaves the disk at the
new version while the process runs the old one. The disk version check
missed it. The doctor now compares the process start (btime+ field 22 of
/proc/<pid>/stat) with the mtime of the module it would import, with 2 s
slack, and saysiniciou <data>, antes do codigo que carregaria hoje.
Entries carryreason(older_version|code_newer_than_process).
Known limitation
- A wrapper whose own venv also has conscio installed is still listed. The
interpreter truthfully answers "importable" and the cmdline carries
conscio-mcpafter--(measured: the Hermesmcp_stdio_watchdog.py,
whose venv has 4.7.2). Its child is judged on its own. Planned for v4.8.
v4.7.2 — Mail that nobody reads is now visible
Patch from the relay message audit of 2026-09-24 (Hermes, Antigravity,
zcode, Claude): messages were parked for days with nobody knowing, and the
tool meant to answer "why doesn't X answer" hung instead.
Fixed
relay doctorexecuted arbitrary binaries. The version probe ran
<exe> -c "import conscio; ..."for EVERY process in /proc, before even
checking whether it was Conscio. zcode, antigravity and gnome-keyring-daemon
were spawned with-c, forking daemons outlived the 5s kill (9 stray
processes measured), and doctor hung for minutes. Only Conscio processes
are inspected now, and only Python interpreters are probed (forclaude,
-cis--continue). Deleted binaries are never executed.- Broadcast fed dead peers. A card silent for 20 days still received
every broadcast. Local peers silent past 3 days are skipped and listed in
the newskippedfield. Paired remotes are never judged: their age is
the pairing time. - Direct send to a dormant peer said only "ok". It still delivers (the
sender named the peer), but now returns awarningwith how long it has
been silent. directory.prunenever ran in production. It existed and was
tested, but nothing called it. It now runs on the send path with the rest
of retention, never collects a paired remote, and re-reads the card
right before deleting it (an agent that came back is not collected).- Phantom space from an unsubstituted plugin variable. Codex installed
the Claude Code plugin and ran its.mcp.jsonverbatim: it does not
substitute${CLAUDE_PLUGIN_DATA}, soconscio-mcpreceived the literal
string and created a${CLAUDE_PLUGIN_DATA}/spacedirectory relative to
its working directory — inside the repo, untracked, onegit add .away
from committing a database.conscio-mcpnow refuses a--storagethat
still contains${VAR}or$VAR: it exits 2, names the variable, and
creates nothing. Hosts that substitute the variable (Claude Code, zcode)
are unaffected.
Added
relay doctorreports mailboxes. For each local agent: unconsumed
messages, the oldest one's age, by sender; messages parked in the spool;
DORMANT state. It also warns about spools with mail but no card (nobody
will ingest them). Read-only:mailbox.waitingopens the db with
mode=ro, never creates a schema, never quarantines.
Changed
relay_broadcastreturnsskippedalongsidesent/errors.
v4.7.1 — The audit lands; the loop closes
Post-ship audit round (hostile, by the Gemini executor and verified by the
orchestrator): 14 findings, 12 fixed, 2 routed to the roadmap. Everything
below is measured against the live codebase.
Added
-
Decision-outcome CLI — the calibration loop closes.
conscio outcomes listandconscio outcomes resolve <ref> <outcome> --evidence ...
attach the real outcome to captured decisions. Before this, every council
capture stayed pending forever — nothing in production could resolve
them, making measured calibration unreachable outside tests (the orphan
defect: tests proved the method worked; nothing proved a production
path called it). Ghost resolves and invalid outcomes are visible errors. -
Host identity derived from environment presence. When neither the
--identity-*flags nor the env vars are set, the server now knows its
host from the PRESENCE of host-specific environment keys (ZCode,
Antigravity, Claude Code, Hermes, OpenCode). The golden rule, born from
a live audit that found shell tokens in a server's environ: detection
reads key NAMES only — values are never read. No recognizable signal
means empty identity withsource=none(the v4.7 absence contract —
never a guess). Family derives strictly from the model name; no forced
fallbacks. Final precedence: CLI flag > env var > host derivation > empty. -
CONSCIO_IDENTITY_MODEL/_FAMILIA/_RUNTIME/_PAPELenv
vars — per-host identity for hosts that cannot override MCP args
(plugin-shipped configs). Precedence: CLI flag > env var > empty. Without
them, a server boot republishes the card with explicit empty strings and
wipes the identity an agent published by hand.
Fixed
- Native embedding failure is no longer silent. A bare
pip install consciowithoutsentence-transformershad semantic recall off with
only a debug-level log. Now: WARNING naming the remedy (install the
package or opt into a daemon viaCONSCIO_EMBED_BACKEND). - Coherence epistemic score honors the None contract. Cold start
(calibrationNone) was aTypeErrorswallowed by a bareexcept;
it is now an explicit branch — absence is a contract, not an exception
to mask. conscio/USAGE.mdresynced from the root — the packaged copy had
drifted (297 vs 580 lines).
Fixed (bug-hunt round)
- Evaluate Clarity no longer inflates on a broken detector. The
contradiction counter'sexcept: passsilently reported a clean score
when the world read failed; the failure now logs and the axis reports
the count as UNMEASURED. - HNSW signature metadata opens with busy_timeout — concurrent agents
validating the vector signature no longer die ondatabase is locked. - Relay token and tick cursor writes are atomic (tmp+rename) — a crash
mid-write can no longer leave a truncated token or a torn cursor that
silently re-ingests the window.
Changed (docs — the standing rigor rule)
- CONTRIBUTING.md rewritten against measured truth: one test file per
process (the oldpytest tests/ -qOOMs), test counts re-measured per
release instead of frozen numbers, pyright (not mypy), line length 100,
the ConfidenceValue contract, native-first embeddings, and the
fake-module-in-sys.modulespattern for optional dependencies. - USAGE.md: 8 console scripts (reactor + relay-bridge were missing);
native-first embedding policy (the fallback-chain text was stale);
storage defaults corrected (library default vs the CLI's live-space
resolution;$HERMES_HOMEis legacy). - Docs speak spaces, not internal filenames. Storage sections describe
the space — one directory per agent host, one file per concern — and no
longer cite internal database filenames. - docs/roadmap.md extended to 4.7.0 with the measured suite count and
a candidate-directions section distilled from the idea banks (durable
shadow receipts, execution verification, provenance chain, distributed
consensus, per-runtime evidence producers, decision-model support).
v4.7.0 — Calibration you can trust
Every confidence-like number the framework emits now carries its nature, and
the numbers that only looked like probabilities are gone. The reference is
Laya/Jev — typed decisions, proper scoring rules, calibration against
outcomes — adapted into a local-first, deterministic framework. No Kaggle
fine-tune, no external API in the runtime.
Changed
-
MetaCognition.calibration_score()no longer fabricates a prior. The
old1 - abs(E[C] - E[Y])macro-distance called a confident-wrong agent
"perfectly calibrated" when mean confidence equaled accuracy. It is now a
compatibility projection:NonebelowMIN_CALIBRATION_SAMPLES, otherwise
1 - ECE(5 equal-width bins).calibration()returns the full
ConfidenceValue(category, value, samples, metric). -
Confidence is multi-categoría.
ConfidenceValue(new
conscio/calibration.py) freezes four tiers:none(absence — value is
None, never a fabricated prior),asserted(declared deterministic
heuristic),derived(posterior over observed data),measured(ECE/Brier
against ground truth, samples + metric required).as_gate_input()raises
onnone— branch on the category, do not guess. ECE/Brier carry
lower_is_better=True;accuracydoes not. -
The council separates agreement from recommendation.
agreementis
1 - normalized_entropy(vote_counts)— four unanimous vetoes now read as
agreement 1.0 with avetorecommendation (the old table called it 0.1,
"disagreement").consensus_strengthsurvives as a deprecated alias. -
Coherence cold start is honest. The confidence field carries
ConfidenceValue—nonewhen evidence is insufficient. The0.85
default survives only in the legacy scalar projection that no gate reads;
theunmeasuredmechanism is preserved.
Fixed
-
The act fast-path no longer launders global calibration into per-action
safety. A globally "perfect" agent used to auto-pass tools it had never
run. Safety now comes from a per-tool Beta(1,1) posterior over the tool's
own ledger outcomes (p = (1+successes)/(2+attempts), derived, samples
exposed); zero attempts isnoneand never auto-executes.
AuditVerdict.confidenceisfloat | None— absence carries no number. -
Cold-start consumers of
calibration_score()no longer crash or guess.
TrustMatrix.autonomy_level(None >= 0.6 TypeError),max_action_retries
(int * None) andfast_path_ok()now treat absence as no-earned-trust:
autonomy stays L1, retries keep the warmup floor, the bypass gate fails. -
bench sabotage calibration treats
Noneconfidence as full suspicion.
Added
-
Outcome store (P1 ground truth): append-only
decision_outcomeswith
provenance —source(council/evaluate/squad/coherence),decision_ref
(unique, idempotent), immutablesnapshot,outcome
(pending/success/failure/reverted/false_positive),outcome_ts,
evidence_ref. The engine wires it and the council captures every decision
best-effort; verdicts arrive viaresolve()when the real outcome is known.
Pending is never a failure; a ghost resolve is visible, not silent.
Temperature-refit (Laya-styleT(task_type, option_count)) is deliberately
deferred until this store accumulates held-out outcomes. -
Vector-space signature:
{backend, model, dimension, version}persisted
on first write and validated before ingest/query — mixed-model signatures
are rejected before they corrupt recall.
Changed (embeddings)
- Embeddings are native-only by default.
EmbeddingProviderno longer
probes Ollama/LM Studio on boot: unsetCONSCIO_EMBED_BACKENDmeans
sentence_transformersin-process, zero network probes, and an explicit
failure when native is unavailable — never a silent daemon takeover.
CONSCIO_EMBED_BACKEND=ollama|openaiopts into a daemon;autois the
legacy fallback chain with a WARNING naming the selected backend.
semantic.pyuses the same factory instead of instantiatingOllamaEmbedder
directly.
v4.6.8 — The council keeps its word; the card survives the writer that doesn't know
Two production-measured contracts land together. First, the council was
always meant to be deterministic — the critic's automatic LLM path made an
attached adapter alter votes and made LLM availability a de-facto
prerequisite for the 4th voice. Second, publish_self rebuilt the relay
card from scratch on every republish: one blind call from the heartbeat
writer erased identity fields, reverted capabilities to the parameter
default, and dropped any key this version doesn't know — three erasure
classes, measured against the published 4.6.7 artifact.
Changed
-
Council is deterministic by contract. The critic voice never consults
an LLM adapter;conscio.gates._get_adapterremoved as dead code. Proof:
anExplodingAdapterattached to an awake engine — any adapter call fails
test_council_never_calls_llm_adapter— plus a live-engine test that runs
eng.council()end-to-end through the ModeRouter in all four output modes.
Optional LLM analysis remains available in squads viause_llm=True;
the council never calls it. -
publish_selfis now a sentinel read-modify-write.None(the new
default) means "I don't know — preserve"; an explicit non-None value means
"I know — write". The new card is born from the old one, so keys this
version doesn't know survive by construction, not by nominal list. This
subsumes the two ad-hoc rules (the halls loop and the spaceherdado
block) into one: who doesn't pass, doesn't touch. Space keeps its 4.6.7
precedence — explicit wins, blind inherits. -
The blind writer writes
None, not"". The reactor — the heartbeat
writer this fix exists for — converted a missing db identity to""
before callingpublish_self, and an empty string is non-None, so the
sentinel let it through and the erasure continued for the real production
case. Reactors now passNonewhen the db doesn't know a field; the
server passesspace=Nonewhen it has no storage to resolve.
Added
conscio relay doctorwarns about stale live processes. After an
upgrade, any long-running process still on the old version keeps writing
cards with old rules (empty strings, no sentinel) and can erase fields the
new version introduced. The doctor scans/procfor live Conscio
processes, resolves the running version three ways (--report-versionflag,
uvx --from conscio==pin, venv dist-info walk), and prints an actionable
warning per stale process. Measured live on this machine: it found five
survivors of the last reboot running 4.5.0 against an installed 4.6.7.
Docs
- Council docs swept against the code: 4-voice deterministic everywhere.
The "Optional LLM Critic" sentence (a double lie — four voices, and no LLM)
removed fromdocs/guides/mcp.md; the surface-mode tableultrarow
corrected; USAGE heuristic table 3→4; architecture guide 3→4; the stale
gates.pydocstring that still promised "No LLM calls except
council.critic" fixed to state the actual contract.
v4.6.7 — The CLI learns where the live space is
The package never knew where the live space was. Hooks only got it right because
Claude Code injects --storage "${CLAUDE_PLUGIN_DATA}/space" into every line of
hooks.json — measured: zero references to plugins/data or
CLAUDE_PLUGIN_ROOT exist anywhere in conscio/**/*.py. That correctness was
borrowed from the host and did not survive a bare shell, so everything a person
typed fell through to the neutral default and answered, confidently, about a
space nobody runs.
Measured before and after on the same fixture:
| before | after | |
|---|---|---|
conscio relay quarantine |
total: 0 |
total: 1 |
db embedded in the unit relay service prints |
the home's | the live space |
conscio capabilities |
names the default | names the live space |
Added
-
conscio.space.resolve_live_space()— one resolver, four declared rungs:
--storage,CONSCIO_SPACE, the directory card, then the neutral default,
which is no longer invisible because provenance returns with the path. It
lives in its own module because reading a card fromnoosphere/paths.pywould
close an import cycle throughliaison.directory → agents → mailbox. -
spaceon the directory card: the agent that holds a space publishes
where it is. Only the MCP server writes it — the reactor, the card's other
writer, has no access to a space and so cannot publish a wrong one. -
--storageonrelay quarantine,relay service,tick,watcherand
reactor, which had only--liaison-db. -
conscio relay forget <id>— retire a peer's address from this machine's
directory. A card can outlive whatever published it, anddirectory.forget
had no way for an operator to reach it, so the remedy was editing JSON by
hand. It touches neither the space nor the identity, and an agent that is
merely idle republishes on its next heartbeat: it cannot silence a live peer,
only retire a dead one. -
A guard over
assets/commands/*.md: no shipped command may consume a
$CONSCIO_*variable, because nothing sets one for a slash command.
Fixed
-
/conscio:awakeranconscio daemon --storage "$CONSCIO_SPACE", and
nothing in the repository ever set that variable. Every link measured: the
flag expanded empty;installer/binding.pywaves an empty storage through as
"default storage; nothing to validate"; the engine falls to its own default
andmkdirs it;daemon.pythen mints an identity there. A shipped command
started long-lived proactive cognition against the dead space. -
The daemon never reached the resolver, so the fix above was not enough on
its own. Resolving once at the top also gives it a real pidfile, where before
it wasNonewhenever no space was passed — silently disabling the
single-daemon invariant for exactly the callers that pass none. -
Fourteen call sites across
cli.py,noosphere/cli.py, the four relay
modules,daemon.py,observatory/server.pyandhub/server.pyresolved a
space or a database without knowing where the live one was.noosphere idwas
the sharpest: it reachesidentity.load_or_create, which writes — forging a
second identity for the agent in a space nobody reads. -
The Hub defaulted to a
~/.hermespath under a comment claiming it
matched the engine's. It had not matched since the engine went neutral, so on
such an install the Hub wrote its daemon control file where no daemon reads
and the awake toggle silently did nothing. -
relay serviceand the relay modules now expand~in an explicit
--liaison-db, which they previously took literally. An all-whitespace
--storageis no longer taken as a space name.
Upgrading — read this if you run a service or share a machine
A command may now refuse instead of answering. When more than one agent on a
machine has published a space, nothing picks between them: the command says so
and lists the candidates. Name the one you mean with --storage, or set
CONSCIO_SELF_ID. Silently choosing was the defect being fixed.
A systemd unit generated before this release carries no identity, so on a
multi-agent machine the reactor exits at boot rather than deliver to the wrong
mailbox — loudly, with the remedy in the message. Regenerate it with
conscio relay service --id <your id>, which now bakes the identity in.
Only agents running this release publish a space at all, so this appears the
first time a second agent is upgraded. A card written before this release
carries none, and the resolver never considers it.
Service entrypoints (conscio-reactor, conscio-observatory) let the refusal
propagate rather than exiting quietly, so the reason lands in the journal. Only
conscio <subcommand> prints it as a plain message.
Notes
-
A card may steer the resolver only past three filters, each catching what the
others let through: it must not name the default space (by construction the
artifact of this bug), its space must still exist (the one unambiguous sign an
agent is gone rather than idle), and that space'sinstance.jsonmust agree
about who owns it. Card age is deliberately not consulted:is_liveis "só
para exibição — nunca para endereçar", and a week away would otherwise retire
a perfectly live space. -
A card cannot clear its space, only replace it: an absent value inherits
rather than erases, which is what stops a background republish — knowing no
space — from wiping what the server wrote. An address that outlived its agent
is retired withrelay forgetinstead. -
This release does not remove identities already minted in a default space. It
closes the factory; clearing the yard is a separate, destructive decision.
v4.6.6 — Identity travels with the consent
4.6.5 moved the opt-in capabilities into the space so a plugin update would stop
erasing them, and left the identity conditioned on args.enable_relay. On the
marketplace path — the one that carries no flag — that exposed the relay
blind: the tools were advertised and could not match a single message.
Fixed
-
The marketplace path served the relay with an empty sender. Measured on
the same space, with three messages addressed to its identity and zero flags:
before,relay_peers.selfreturned""andrelay_inboxreturned 0 of 3;
after,selfis the space'sinstance_idand the inbox returns 3. The
condition is now the RESOLVED capability, never the flag. -
The blind path also pointed at the wrong database. With no identity the
mailbox fell back to the home's~/.conscio/liaison.dbinstead of the
space's. Measured by resolving both paths:default_db()→
<home>/.conscio/liaison.db,resolve_db(space)→<space>/liaison.db.
(Measured as a pointer; the write to the global db was not reproduced.) -
The remedy named a command that wrote to another space. The
SessionStart
warning told the reader to runconscio capabilities enable relaywith no
--storage, so the consent landed in~/.conscio/consciousnesswhile the
warning had just read the plugin's space. The command now carries the space it
read; with two lost capabilities it names both. -
The wiring, not just the function. Six of the seven tests call
resolve_identity()directly, so reverting the fix to the flag leaves them
green and only
test_mcp_identity_wiring.py::test_main_wires_the_identity_from_the_space
red — andmain()is where the original bug lived. Measured by sabotage.
Added
-
Every verdict carries why it is what it is.
check()collapsed six
distinct situations into(UNSUPPORTED, ""), an empty receipt that made "I
could not look" indistinguishable from "there is nothing there". The receipt
is now a closed vocabulary —why:no_act,why:no_obs,why:budget,
why:window,why:unreadable,why:blind_interp, plusobs:<id>for
VERIFIED andabsent/scanned=<n>for CONTRADICTED — with a fixed precedence
(shape → corpus → config → session → format → runtime) so that two true
motives cannot produce different receipts on different runs. The receipt is
never a verdict: the outcome does not change because of it. -
A hedged claim is not an assertion, and the gate is a family. That
"talvez" and "poderia" did not leak was an accident of conjugation, not
coverage. The families are doubt, belief, supposition, hypothesis and
appearance, in both languages, with the complementiser rule that keepsacho quea belief whileachei o arquivostays a finding. Measured on the corpus
intests/test_honesty_modality.py: 28 modalized phrases blocked, 13 true
ones preserved. Breaking the gate on purpose turns 28 red and keeps 13
green.
The numbers that did not survive re-measurement
The report describing this cycle said "18 modalized against 12 true" and "51
messages blind". Re-measured here: the corpus holds 28 and 13 (counted from
ast, not from prose), and the blind inbox was reproduced with a locally built
corpus of three. The write to the global liaison.db was not reproduced at all.
Docs corrected against the running server
Counted by starting the server and listing the advertised surface: lite 10,
balanced 19, high 27, ultra 37. The guide said 21 for high and that
ultra adds "the remaining 16" (it adds 10). The flag paragraph said
--enable-relay adds 5 tools and --can-create-halls 7 more; each adds one
dispatcher tool — conscio_relay with 5 operations, conscio_hall with 7 — and
the per-operation names stay callable but unadvertised. Maximum advertised with
act, review, relay and halls together: 46, not 49.