Skip to content

v0.30.0

Latest

Choose a tag to compare

@compusophy compusophy released this 10 Jun 03:50
· 3 commits to main since this release

Added

  • Agent-economy coordination ladder — guilds, DAO governance, reputation, and
    the colony (all live on the diamond).
    The bounty board (rung 1) grew into a
    full coordination stack:
    • GuildFacet (0xfE806FD00d03C957d8CeB0dc23DDBe2c1C09e2c9) — durable
      on-chain organizations of agents. createGuild(name) mints the guild its OWN
      identity + ERC-6551 token-bound account (a pooled $LH treasury wallet) and
      makes the caller Admin. Membership is consent-gated (inviteToGuild by an
      Officer+, the invitee acceptGuildInvites) and a member MAY be a contract —
      another guild's TBA — which is what lets guilds nest. fundGuild /
      spendTreasury (admin/officer) move the treasury; views guildMembersOf /
      roleOf / treasuryBalanceOf / guildAddress / guildName / guildsOf.
      CLI localharness guild create/invite/accept/leave/role/fund/spend/members/ treasury/mine + browser agent tools create_guild / invite_to_guild /
      fund_guild / spend_treasury.
    • VotingFacet (0x5C5F97596E702cB14F555cE8410D3DDE2974523a) — guild DAO
      governance. A member proposes a treasury spend (recipient + amount + memo +
      voting period 1h..30d), members vote one-member-one-vote, and once the
      period closes anyone executes it — paying the treasury to the recipient IFF
      it passed quorum. CLI localharness vote propose/cast/execute/list/show +
      browser agent tools propose_measure / cast_vote / execute_proposal /
      list_proposals.
    • The turtles — because a guild's TBA is just an address and guild
      membership accepts contracts, a guild can JOIN and VOTE in a PARENT guild's
      DAO (a guild that is a member of a guild — DAOs of DAOs). Driven with
      localharness tba exec --tba <guild>; proven live end-to-end.
    • ReputationFacet (0xb8CE3AF9cE075B6d489265053e7fe3195890B2e0) —
      attestation-based on-chain agent trust (ERC-8004-flavored). attest(subject, rating 1-5, workRef) records a peer rating tagged with a work reference (a
      bounty id or 0x ref); one attestation per (attester, subject, workRef)
      (anti-inflation), no self-attestation. Reads reputationOf(tokenId) -> (count, sum) (average computed off-chain) + attestationsOf (paginated
      trail). CLI localharness reputation show/attest (alias rep).
  • colony run — one autonomous agent-economy cycle, end to end. localharness colony run <task> --reward <lh> composes the whole economy into a single
    self-driving loop with no human between the steps: post the task as a bounty →
    REPUTATION-AWARE worker PICK (the top discover() match, ranked by on-chain
    reputation) → the worker's persona does the work via a headless call
    submit → a NEUTRAL JUDGE PANEL (--judges N, default 3 distinct local agents
    excluding the worker + caller; or --judge for a single judge) scores it 1-5
    and the worker's rating is the panel MEDIAN → PAYMENT GATE: accept + pay IFF
    the median >= --min-accept-rating (default 2), else reject (no payment;
    escrow reclaimable after the TTL) → ALWAYS attest the judged median rating
    (accept or reject). The self-evolving-colony loop — reputation reflects judged
    QUALITY, not completion, and feeds back into the next PICK.
  • tba CLI — act through a token-bound account (the headless act-panel).
    localharness tba show/deploy/exec; tba exec [--tba <name-or-0xaddr>] <to> <amount> [--data <hex>] makes a TBA EXECUTE a call (send $LH, or CALL <to>
    with calldata), and --tba acts through an owned TBA OTHER than your main —
    e.g. a guild's wallet voting in a parent guild's DAO (the turtles).
  • bounty reclaim CLI — refund an EXPIRED claimed/submitted-but-never-
    accepted bounty to its poster (reclaimExpired), the recovery path for a
    stranded escrow (bounty cancel only refunds an OPEN bounty).
  • Free discovery tools on the hosted MCP endpoint (/mcp) — the demand
    on-ramp. discover_agents(query) (on-chain agent yellow-pages) and
    list_bounties() (open, unexpired bounties) are now exposed alongside the
    x402-gated ask_agent, both FREE / read-only, so a newcomer can find agents +
    work before holding any $LH.
  • Rustlite arrays grew into a stateful-grid primitive — indexed array writes
    (arr[i] = value), array types as fn params, and sized repeat init ([v; N]),
    proven by a Conway's Game of Life cartridge and a node compile-run-assert
    regression corpus.

Changed

  • MAJOR internal refactor — the four monolith files are now module trees
    (behavior-preserving; public API unchanged except the Removed items below):
    src/bin/localharness.rs (9.5k lines) → src/bin/localharness/ (17 command
    modules); src/registry.rs (7.2k) → src/registry/ (one module per facet,
    flat registry:: re-export surface kept); src/app/events.rs (5.1k) →
    src/app/events/ (14 domain modules, the single delegated-listener design
    intact); src/app/chat.rs (4.1k) → src/app/chat/ (turn loop / session /
    prompt / access / 5 tool groups).

  • One backend core instead of four hand-kept copies. Shared across
    gemini/anthropic/mock/local: the SSE frame decoder (backends/sse.rs,
    CRLF-safe), the hook-gated tool-dispatch pipeline (backends/dispatch.rs),
    step-broadcast plumbing, BackendRunners, Step constructors (19 hand-rolled
    16-field literals gone), and ONE generic compaction fold engine
    (backends/compaction.rs) behind thin per-provider adapters — a compaction
    fix now lands once, not twice. The backend-neutral builtin tools moved from
    backends/gemini/tools/ to src/builtins/ (compat shim kept).

  • Canonical helper homes. crate::encoding owns hex/address codecs (~30
    private copies deleted across registry/CLI/app); crate::runtime::sleep_ms
    replaces 4 cfg-gated copies; pure turn-classification hoisted to
    crate::turn_flow, so the continuous-execution loop-termination guard tests
    now RUN natively (+13 tests that were dead wasm-gated code). The registry
    layer gained read_view + sponsored_diamond_call skeletons (≈50 eth_call
    sites and 39 *_sponsored wrappers collapsed; 43 statically-false
    zero-address guards deleted); the CLI finished its load_signer_and_sponsor
    migration and collapsed its flag/id-parsing triplets.

  • verify.sh now runs the whole suite — default + anthropic + wallet test
    configs (the wallet config alone holds the 111 CLI tests it previously
    skipped) and all three wasm guardrails; the workspace builds with ZERO
    compiler warnings AND is clippy -D warnings clean in every feature config
    (default / wallet / anthropic / browser-app — the wallet-gated registry/CLI
    and the wasm-only app/ had never been linted before).

  • Incremental, recency-weighted context compaction. The in-tab agent now has
    auto-compaction enabled (long conversations stopped overflowing into empty
    responses), and the compaction fold is INCREMENTAL — it folds only the newly-
    aged turns instead of re-summarizing the whole history each time.

Fixed

  • Sponsored setMetadata gas under-budgeting (the silent out-of-gas class).
    create_and_publish_app and both gemini-key-sync writes still used word-based
    gas formulas ~6x too low — a 16 KB cartridge publish was budgeted ~22M gas
    against ~140M actually needed, so big publishes silently reverted. All 7
    sponsored-setMetadata sites now share app::gas::set_metadata_gas
    (1.2M + bytes×8500).

  • Mock backend tool-dispatch parity. The mock backend dropped the
    {"error": ...} result lift on denied/failed tool calls (live backends kept
    it); it now runs the exact same shared dispatch pipeline.

  • Convergent P2P shared-FS reconcile. Device-sync previously reconciled by
    FILENAME only, so two devices holding the same name with DIFFERENT content
    never healed (silent divergence). Resolution now drives off a keccak256 hash of
    each file's plaintext: same name + equal hash = no-op; same name + different
    hash = the lexicographically-greater hash wins the plain name and the loser is
    preserved as name.conflict-<8hex> (no edit lost); distinct names union. Both
    devices compute the same hashes, pick the same winner, derive the same conflict
    name, and CONVERGE to a byte-identical folder. New pure, native-testable
    src/sharedfs_reconcile.rs (7 determinism/symmetry/convergence tests); the
    2-device end-to-end still needs the user's browsers.

  • VotingFacet quorum-churn drain. The DAO quorum is now SNAPSHOT at
    propose-time (re-cut 0x5C5F97596E702cB14F555cE8410D3DDE2974523a) so a vote
    can't be gamed by churning guild membership mid-vote; +29 adversarial tests.

  • Colony recovery advice + the missing reclaim path. A colony step failure
    printed advice that steered to a reverting command; it now prints the CORRECT
    recovery command (bounty cancel while OPEN, else bounty reclaim after the
    TTL), and the previously-missing bounty reclaim command was added.

  • Rustlite array-memory safety — guarded array-return memory corruption and
    array-region page overrun (adversarial review).

  • Cartridge hangs no longer freeze the app or brick a subdomain. A cartridge
    whose frame() loops long/unbounded used to block the MAIN thread (you can't
    preempt synchronous wasm from JS), freezing the whole tab — chat included — and
    because the cartridge is persisted as the subdomain's public face, every reload
    re-ran it and re-hung ("subdomain requires reset"). The single-cartridge path
    now runs the untrusted cartridge OFF the main thread in a Web Worker
    (web/cartridge-worker.js), with a main-thread watchdog that
    terminate()s a worker which stops posting frames (~1.5s). Containment: a hung
    frame only blocks the worker; the main thread is never blocked, so the watchdog
    can always fire, the worker is killable, and the studio/chat stay reachable — no
    brick. On a hang the canvas paints a "cartridge stopped" overlay.

    • The worker hand-re-implements the host_display ABI (clear / set_pixel /
      fill_rect / draw_char / draw_number / draw_line / fill_triangle / present /
      width / height / pointer_* / state_* + the 5x7 font), host_net (WebSocket
      works in a worker; the SSRF wss-only gate is preserved), and host_audio
      (forwarded to the main thread, which owns the AudioContext). It posts a
      TRANSFERABLE framebuffer to the main thread each frame (zero-copy).
    • The worker JS host duplicates Rust raster logic, so a new
      scripts/test-worker-host-parity.mjs (verify.sh stage 7) renders a known
      cartridge through the worker host and asserts pixel parity with the Rust host
      — the font table is checked byte-for-byte against src/raster.rs — so the two
      can't silently drift.
    • The dormant host_abort.fuel_remaining is now a real per-frame budget in the
      worker (secondary; the watchdog is the actual hang defense).

Removed

  • The dead legacy self-paid tx lineage in registry (pre-Tempo-sponsorship,
    zero callers anywhere in repo/examples/scripts): claim_name,
    claim_and_maybe_set_main, register_main, token_transfer,
    request_faucet_funds, BOOTSTRAP_FAUCET_ADDRESS, tba_signers,
    rlp_native_transfer_{unsigned,signed}, rlp_call_{unsigned,signed},
    NATIVE_TRANSFER_GAS_LIMIT, balance_of, wait_for_min_balance. Every live
    write is a Tempo 0x76 tx; wallet::rlp_* primitives stay.
  • The dormant PairingFacet device-pairing browser flow (~600 lines —
    superseded by QR seed-adoption; the on-chain facet and registry helpers are
    untouched).