Skip to content

Releases: Neguiolidas/Conscio

v4.8.2 — The Promptor refines, and zcode sees the update

Choose a tag to compare

@github-actions github-actions released this 03 Oct 23:28

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 voting flag (default true). The
    Promptor sets voting = false, so convene_squad excludes it from
    recommendation and votes_summary while its payload still rides in
    voices with an empty vote — 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 lights only.
  • 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_experts schema description,
    engine.squad_experts docstring, 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 — the conscio entry 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.py keeps four copies in lockstep: the
    marketplace entry, the shipped plugin.json, the .mcp.json uvx pin
    and conscio.__version__. docs/RELEASING.md step 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, and conscio_relay send
    returned ok for 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,
    and send returns a warning naming the peer and the URL that did not
    answer. broadcast carries the same warning on that peer's sent
    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

Choose a tag to compare

@github-actions github-actions released this 03 Oct 11:59

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_check maintenance goal expires after
    its act and is regenerated only after MAINTENANCE_COOLDOWN_MIN = 60 minutes,
    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 whole max_cycles budget. 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 = 120 act 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 writes tokens = 0 rows and still burns quota. When the ceiling
    trips, awake degrades to perceive + reflect, emits the trip on the event bus,
    and the heartbeat's last_run.stopped reads daily_cost_ceiling.
  • No active goals is IDLE, not a failure. A heartbeat with no executable goal
    returns ActStatus.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 of AdapterBadResponse) carrying status.
    FailureGovernor.classify maps 429 → RATE_LIMIT, 401/403 → PERMANENT,
    5xx → PROVIDER_OUTAGE, any other status → MALFORMED_STREAM.
  • Fast-fail on rate limit and outage. On RATE_LIMIT or PROVIDER_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. TIMEOUT still
    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
    existing error column (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 to host_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_observations session scope. The default scope="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 explicit session_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 no project was
    given, the most recent session among observations recorded without one. If
    none exists it answers INVALID_PARAMS saying 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 sha1 digests (short
    ids in integrations/neurata.py and outcomes.py) pass
    usedforsecurity=False; the relay reactor's shell=True call
    runs the operator's own notify pipeline with the payload on stdin, never
    interpolated, and carries a # nosec B602 annotation that says so.
  • Dead code removed. OutputGateway loses the unused _failure_gov
    attribute and failure_governor parameter, 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; .gitignore and mkdocs exclude_docs now cover them, along
    with local per-agent harness files.
  • uv.lock back in sync. The lockfile was missing the build dev
    dependency that pyproject.toml has declared since v4.0.0, so
    uv lock --check failed on a clean checkout.

v4.8.0 — The space survives, the machine has a board, the council can be measured

Choose a tag to compare

@github-actions github-actions released this 28 Sep 10:50

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=True signals the caller to create or update the
    pointer):
    • B0 (Legacy): unmigrated plugin space; prints stderr announcement to run
      conscio space migrate and uses the legacy path byte-for-byte.
    • B1 (Bound): valid space-pointer.json pointing 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 if migrated-from.json tombstone 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 with repair_pointer=True.
  • Pointer minting with exclusive flock (conscio/installer/spaces.py).
    Concurrent boots serialize via an exclusive flock on
    ~/.conscio/instances/.minting-<slug> (5 s timeout) with a mandatory re-read of
    instance.json upon acquisition to prevent ID divergence. Degrades safely with
    a warning on filesystems without full lock support (ENOLCK / EOPNOTSUPP).
  • Refusal markers (space-refused.json). When target is None
    (B3/B4/B5/lock), the server writes an atomic space-refused.json marker 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:
    1. acquire .migrating-<slug> lock;
    2. create timestamped backup in ~/.conscio/backups/pre-migrate-* (keeps 2
      generations);
    3. move content of space/ while preserving the folder;
    4. write migrated-from.json tombstone in durable root;
    5. atomically write space-pointer.json in plugin directory;
    6. remove space-refused.json;
    7. release migration lock;
    8. 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.
  • 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.json tombstones.
    • 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.json refusal markers with state and age.

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
    shared decision_adapter transport (config: an empty judge
    marker block plus a decision_adapter block — see USAGE.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's question,
    context and, when present, options leave 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 in USAGE.md). The per-voice weight
    table in conscio/gates.py is commented with the dev round that
    produced each value.
  • Readiness gate. A proceed only leaves the council when the
    engine is ready — not in action_lockdown, not in a critical
    metabolic state, and, when a coherence score exists, coherence ≥
    0.5. Not ready ⇒ lowered to hold, reasons in gate_reason; the
    gate never promotes. New additive result fields: mode,
    judge_status, gate_reason, and the judge report 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); the conscio_council entry
    in docs/guides/mcp.md now 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_board MCP tool + conscio ambient CLI. 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, and wake <id> --dry-run. The MCP tool is a single
    conscio_board dispatch; the actor is always the server's own identity —
    there is no as= argument.
  • The ambient node rides the reactor tick. While enabled it notices
    assigned work over the relay (a task_dispatch carrying only the task id),
    re-notifies a stalled reviewer on a cap, and — through the connector gate —
    may wake a non-live agent. A broken conscio.ambient package costs the node
    and never a relay delivery.
  • Off by default. Without the <relay_root>/ambient/enabled flag file the
    node gives its sweep back and touches nothing (conscio ambient enable
    creates it). The board and CLI keep working while disabled.
  • board.propose travels over the relay. The one board write a remote
    machine may perform: a peer asks for work and it lands as a proposed task
    with creator = sender and origin = <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's wake_budget_per_day
    defaults to 0, so nobody is woken until the owner opts them in.
  • The claude-bg connector. The one connector in this release. A wake
    runs claude --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 the backgrounded · <id> line. A
    spawn that exits 0 with an id is a success; otherwise a 429/rate-limit
    message is recorded as rate_limited and anything else as spawn_error.
    Liveness reads claude agents --json: working is live; done, failed or
    a session missing from the list is not; blocked, an unrecognised state, a
    non-zero exit or output t...
Read more

v4.7.3 — The doctor asks the process, not the disk

Choose a tag to compare

@github-actions github-actions released this 25 Sep 01:34

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 doctor asks 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 own PATH) and reproduces that
    process's sys.path[0], PYTHON* env and -I/-P flags. The doctor's own
    PYTHONPATH and 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 ~/.local and 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: their Version is
    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 doctor flags 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 says iniciou <data>, antes do codigo que carregaria hoje.
    Entries carry reason (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-mcp after -- (measured: the Hermes mcp_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

Choose a tag to compare

@github-actions github-actions released this 24 Sep 20:54

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 doctor executed 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 (for claude,
    -c is --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 new skipped field. 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 a warning with how long it has
    been silent.
  • directory.prune never 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.json verbatim: it does not
    substitute ${CLAUDE_PLUGIN_DATA}, so conscio-mcp received the literal
    string and created a ${CLAUDE_PLUGIN_DATA}/space directory relative to
    its working directory — inside the repo, untracked, one git add . away
    from committing a database. conscio-mcp now refuses a --storage that
    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 doctor reports 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.waiting opens the db with
    mode=ro, never creates a schema, never quarantines.

Changed

  • relay_broadcast returns skipped alongside sent/errors.

v4.7.1 — The audit lands; the loop closes

Choose a tag to compare

@github-actions github-actions released this 23 Sep 23:25

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 list and conscio 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 with source=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 / _PAPEL env
    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 conscio without sentence-transformers had semantic recall off with
    only a debug-level log. Now: WARNING naming the remedy (install the
    package or opt into a daemon via CONSCIO_EMBED_BACKEND).
  • Coherence epistemic score honors the None contract. Cold start
    (calibration None) was a TypeError swallowed by a bare except;
    it is now an explicit branch — absence is a contract, not an exception
    to mask.
  • conscio/USAGE.md resynced 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's except: pass silently 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 on database 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 old pytest tests/ -q OOMs), 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.modules pattern 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_HOME is 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

Choose a tag to compare

@github-actions github-actions released this 23 Sep 14:00

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
    old 1 - 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: None below MIN_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
    on none — branch on the category, do not guess. ECE/Brier carry
    lower_is_better=True; accuracy does not.

  • The council separates agreement from recommendation. agreement is
    1 - normalized_entropy(vote_counts) — four unanimous vetoes now read as
    agreement 1.0 with a veto recommendation (the old table called it 0.1,
    "disagreement"). consensus_strength survives as a deprecated alias.

  • Coherence cold start is honest. The confidence field carries
    ConfidenceValue — none when evidence is insufficient. The 0.85
    default survives only in the legacy scalar projection that no gate reads;
    the unmeasured mechanism 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 is none and never auto-executes.
    AuditVerdict.confidence is float | 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) and fast_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 None confidence as full suspicion.

Added

  • Outcome store (P1 ground truth): append-only decision_outcomes with
    provenance — source (council/evaluate/squad/coherence), decision_ref
    (unique, idempotent), immutable snapshot, 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 via resolve() when the real outcome is known.
    Pending is never a failure; a ghost resolve is visible, not silent.
    Temperature-refit (Laya-style T(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. EmbeddingProvider no longer
    probes Ollama/LM Studio on boot: unset CONSCIO_EMBED_BACKEND means
    sentence_transformers in-process, zero network probes, and an explicit
    failure when native is unavailable — never a silent daemon takeover.
    CONSCIO_EMBED_BACKEND=ollama|openai opts into a daemon; auto is the
    legacy fallback chain with a WARNING naming the selected backend.
    semantic.py uses the same factory instead of instantiating OllamaEmbedder
    directly.

v4.6.8 — The council keeps its word; the card survives the writer that doesn't know

Choose a tag to compare

@github-actions github-actions released this 22 Sep 22:07

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_adapter removed as dead code. Proof:
    an ExplodingAdapter attached 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 via use_llm=True;
    the council never calls it.

  • publish_self is 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 space herdado
    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 calling publish_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 pass None when the db doesn't know a field; the
    server passes space=None when it has no storage to resolve.

Added

  • conscio relay doctor warns 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 /proc for live Conscio
    processes, resolves the running version three ways (--report-version flag,
    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 from docs/guides/mcp.md; the surface-mode table ultra row
    corrected; USAGE heuristic table 3→4; architecture guide 3→4; the stale
    gates.py docstring 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

Choose a tag to compare

@github-actions github-actions released this 22 Sep 01:52

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 from noosphere/paths.py would
    close an import cycle through liaison.directory → agents → mailbox.

  • space on 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.

  • --storage on relay quarantine, relay service, tick, watcher and
    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, and directory.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:awake ran conscio daemon --storage "$CONSCIO_SPACE", and
    nothing in the repository ever set that variable.
    Every link measured: the
    flag expanded empty; installer/binding.py waves an empty storage through as
    "default storage; nothing to validate"; the engine falls to its own default
    and mkdirs it; daemon.py then 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 was None whenever 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.py and hub/server.py resolved a
    space or a database without knowing where the live one was. noosphere id was
    the sharpest: it reaches identity.load_or_create, which writes — forging a
    second identity for the agent in a space nobody reads.

  • The Hub defaulted to a ~/.hermes path 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 service and the relay modules now expand ~ in an explicit
    --liaison-db, which they previously took literally. An all-whitespace
    --storage is 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's instance.json must agree
    about who owns it. Card age is deliberately not consulted: is_live is "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 with relay forget instead.

  • 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

Choose a tag to compare

@github-actions github-actions released this 21 Sep 17:57

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.self returned "" and relay_inbox returned 0 of 3;
    after, self is the space's instance_id and 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.db instead 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 run conscio capabilities enable relay with no
    --storage, so the consent landed in ~/.conscio/consciousness while 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 — and main() 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, plus obs:<id> for
    VERIFIED and absent/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 keeps acho que a belief while achei o arquivo stays a finding. Measured on the corpus
    in tests/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.