Lucille Marketplace: Auctions, Reputation, Audits (v0)
This doc defines the first concrete economic/reputation model for the Lucille job marketplace. Goal: keep it simple to ship now, but compatible with decentralization later (off-chain matching, optional on-chain settlement).
Goals
- Efficient matching of jobs to workers/nodes with predictable cost.
- Incentivize high-quality outputs via rare but serious audits.
- Preserve privacy where possible (redacted listings; minimal disclosure).
- Allow future decentralization: multiple marketplaces, multiple nodes, optional on-chain settlement.
Non-goals (v0)
- Fully trustless on-chain matching.
- Fully private bidding on-chain.
- Complex governance or tokenomics.
Concepts
Actors
- Requester: the agent/node posting a job.
- Worker/Node: an agent/node that executes jobs.
- Marketplace: matching + bidding + settlement logic (may be centralized initially).
- Auditor: (optional) peer reviewer/verifier running checks against results.
Job
A job is a request to execute a kind with payload, optionally time-bound and budgeted.
Key fields (conceptual):
job_idkindpayload(may be redacted)budget_max(maximum willingness to pay)min_rep(minimum reputation requirement; may be hidden)deadline/ SLA hintsprivacy_level: public / redacted / privateaudit_policy: defaults + overrides (see below)result_encryption_public_key(optional): client’s public key; only the supplier encrypts the result with it so only the client can decipher (see Result store and encryption below).
Capability discovery: black-box delegatees
Lucille treats delegatee nodes as black boxes. The protocol assumes nodes may strategically misrepresent their internal capabilities, implementations, confidence, or execution strategy. Because of that, marketplace matching does not rely on capability declarations as a trust anchor.
Why declarations are weak signals
In a competitive marketplace, nodes have incentives to exaggerate:
- capabilities
- available implementations
- confidence in solving a task
- exploratory or synthesis ability
- execution strategy
These claims are cheap to fabricate, so Lucille avoids using them as a primary selection mechanism.
What the marketplace trusts instead
Lucille prefers costly, outcome-based signals:
- successful execution history
- completion reliability
- latency performance
- failure rates
- reputation derived from observed results
This lets capability discovery emerge from historical performance rather than from self-description.
Unknown instincts
The marketplace must still allow jobs whose kinds have little or no prior execution history. Nodes may attempt those jobs even without established specialization. The resulting outcome becomes a strong reputation signal:
- success establishes specialization
- repeated failures reduce future selection likelihood
This is how new capabilities enter the system without adding declaration-heavy protocol rules.
Internal strategy stays internal
Lucille does not model how a node decides to pursue an unfamiliar job. A node may:
- attempt direct execution immediately
- spend time building reusable implementation logic first
- subsidize exploration to expand its future capabilities
These are internal economic decisions by the node, not protocol-level commitments. The protocol only observes outcomes.
Capability formation vs selection
Lucille separates:
- Capability formation: how a node develops skill internally through exploration, synthesis, implementation work, and investment
- Capability selection: how the marketplace chooses who gets work based on reliability, reputation, and observed performance
This separation keeps the protocol simple while allowing specialization to emerge through market dynamics.
Hidden trust thresholds
The marketplace may apply hidden trust thresholds before certain jobs are exposed or awarded. For example, a worker may need enough observed reliability on similar jobs before it is considered eligible.
These thresholds should remain hidden when practical so nodes cannot game them directly.
Telemetry for later model improvements
Although strategy declarations are not trusted, Lucille should retain telemetry that helps analyze how specialization forms over time, such as:
- execution success or failure
- latency
- retry patterns
- task decomposition traces
- whether reusable logic emerged
This data can later inform pricing, reputation, and exploration-incentive design without requiring the protocol to trust cheap declarations today.
Result store and encryption
Agents do not communicate directly. The marketplace holds results so that workers can shut down when done and the client can fetch output later. See Scheduling for how this fits with deferred work and pre-claim.
Client’s public key, only supplier encrypts
- The client (requester) supplies a public key in the job spec (e.g.
result_encryption_public_key). Only the client holds the corresponding private key. - The supplier (worker) is the only one who encrypts: it produces the result, encrypts it with that public key, and stores the ciphertext (e.g. in the marketplace or job result). No one else can decipher.
- The marketplace (and any other party) sees only ciphertext; only the client can read the result.
Encrypted result format (client decryption)
When the worker encrypts the result, job.result has this shape (only the client with the private key can decipher):
encrypted:truealgorithm:"RSA-OAEP-AES256GCM"(hybrid: AES-256-GCM for the payload, RSA-OAEP for the AES key)ciphertext: base64-encoded bytes = 12-byte nonce + AES-GCM ciphertext (result JSON encrypted with AES-256-GCM)wrapped_key: base64-encoded RSA-OAEP ciphertext of the 32-byte AES key (client’s public key was used to encrypt it)
Client decryption: Decode wrapped_key and decrypt with the client’s RSA private key (OAEP, SHA-256) to get the AES key. Decode ciphertext, take the first 12 bytes as the nonce and the rest as the AES-GCM ciphertext; decrypt with the AES key to get the result JSON.
Authenticating the client’s public key (marketplace as CA)
result_encryption_public_key rides in the job payload, so an intermediary that
controls the payload could swap it for its own key — the worker would then
encrypt the result to the attacker. To defeat that, the marketplace acts as a
certificate authority: it holds an Ed25519 key (MARKETPLACE_CA_PRIVATE_KEY)
and signs a binding of {job_id, result_encryption_public_key}.
GET /ca/public-key→ the CA’s Ed25519 public key (PEM). Public; no auth.POST /ca/sign-result-key(auth:X-Marketplace-Key) with{job_id, public_key}→{algorithm: "ed25519", job_id, signature}. The requester puts thatsignaturein the job payload asresult_encryption_key_sig.
The worker verifies the signature against a CA public key it trusts
out-of-band (MARKETPLACE_CA_PUBLIC_KEY, configured in the worker env — not
read from the payload) before encrypting. Policy:
- CA key configured + signature present → must verify, else the job fails (no result is encrypted to an unverified key).
- CA key configured + no signature → allowed unless
LUCILLE_REQUIRE_SIGNED_RESULT_KEY=true. - No CA key configured → no verification (backward compatible default).
The signed message is b"lucille-result-key:v1:" + job_id + b"\n" + public_key_pem.strip().
Authoritative implementation: backend/app/result_key_ca.py; signer:
marketplace/app/ca.py; verifier: worker/result_key_sig.py (kept byte-for-byte identical).
Pre-claim and assurance
- A worker may claim a job before
run_at(e.g. “I will run this atrun_at”). The job moves to a “leased” / claimed state. - Credits for the supplier can be stacked (reserved or escrowed) when the job is claimed, so the worker has skin in the game.
- The client can see that the job is claimed (via poll or event). Once it sees “claimed,” it knows someone has committed to run it and can shut down; it does not need to wait for execution or result.
- If the worker dies or fails before execution, the job is reclaimed (e.g. lease timeout, job back to queued) so another worker can claim it; stacked credits are handled per policy (e.g. slash or return).
Deployment: separate container
The marketplace runs in its own container, which may be deployed on a different node from the backend or workers. This allows:
- Independent scaling and placement of the marketplace.
- Clear separation of concerns (matching, result store, credits) from core API and worker logic.
- Future flexibility for multiple marketplace instances or decentralized deployment.
Integration with the backend (job posting, claim, result storage) is via well-defined APIs; the backend and workers treat the marketplace as a separate service.
Failure scenarios
Marketplace unreachable
When the worker pushes an encrypted result, it retries 3 times with backoff (1s, 2s, 4s) on 5xx, timeout, or connection errors. On 4xx it does not retry. On final failure, the worker logs a structured event; the job still completes on the backend. The marketplace push is best-effort.
Authentication
The marketplace is a separate service with its own env namespace. If MARKETPLACE_API_KEY is set on the marketplace, PUT and GET require the X-Marketplace-Key header. Workers and clients configure MARKETPLACE_API_KEY in their own env independently. If the marketplace requires auth and the worker does not send the key, the push returns 401. 4xx errors are non-retryable; the worker logs the failure and the job still completes on the backend.
In-memory storage (v0)
The marketplace result store uses in-memory dicts. Results are lost on restart. Persistence is left to deployment (e.g. backing store, Redis, object storage).
Configuration
- Marketplace listens on port 8001 by default (configurable via the container). Optional:
MARKETPLACE_API_KEYfor PUT/GET auth. See marketplace/.env.example for ready-made URLs. - Worker: Set
MARKETPLACE_RESULT_URL(e.g.http://lucille-marketplace:8001in Docker,http://localhost:8001for local dev) inenv/worker.env. When a job result is encrypted, the worker will also PUT the result to{MARKETPLACE_RESULT_URL}/results/{job_id}after completing the job via the backend. Omit or leave empty to skip marketplace push; the backend still stores the result injob.result. - Deploy: Core node runs three containers (API, marketplace, worker). Copy
env/worker.env.exampletoenv/worker.envand setWORKER_TOKENand optionallyMARKETPLACE_RESULT_URL.
Auction model (v0): Second-price with eligibility filters
Eligibility
Workers may only bid if:
- They have sufficient observed performance or trust to be considered for the
kind. - They meet requester constraints (e.g., min reputation threshold).
- They accept privacy constraints.
Note: min_rep and similar trust thresholds may be hidden initially. In v0 we assume off-chain matching can apply hidden filters without exposing the exact policy.
Bidding
- Requester posts
budget_max. - Workers submit sealed bids
b_iand declare required_resources (the same list they would pass at claim time: which resources they need and in what mode). Off-chain in v0. - Marketplace uses bids for price and ranking; required resources are not used for eligibility (any eligible worker may bid regardless of current resource availability).
- Marketplace selects the lowest eligible bid.
- Price paid = second-lowest eligible bid (or a floor like
min(budget_max, b_2)), optionally + platform fee.
Rationale: encourages truthful bidding and prevents “race to the bottom” as strongly as first-price.
Hidden close time + wait-for-first-bid (v1)
- Requester sets an auction duration; backend computes
auction_end_at. auction_end_atcan be hidden from bidders (hidden_end_time=true), so bidder-facing APIs expose only open/closed state.- If
wait_for_bid=false, auction closes atauction_end_at. - If
wait_for_bid=true, afterauction_end_atthe auction waits for the first eligible bid and closes immediately when it arrives. - If no eligible bid arrives in grace (default 15 minutes), auction closes as
closed_no_winnerwith reasonno_eligible_bid_in_grace.
Tie-breaking
If bids tie:
- Prefer higher reliability/audit pass rate.
- Then lower latency history.
- Then prefer the worker whose declared required_resources are currently available for the job's user (so the winner is more likely to claim successfully and does not unnecessarily withhold capacity).
- Then random.
Required resources, over-declaration, and mitigation
- Required resources and capacity: Workers declare which resources they need with their bid. The marketplace does not use required resources for eligibility—only for tie-breaking (as above). The backend enforces resource locks at claim time; the auction does not block bidders whose resources are currently held.
- Cost of over-declaring: If a worker declares more resources than it needs, it holds locks and withholds access for other workers. The cost to the system is capacity denial, not payment. Over-declaring is therefore an attack vector (e.g. to block competitors).
- Mitigation: Reputation mitigates this. Reputation is part of the auction score and can include a completion score (or requester rating) that the requester/agent gives when the job completes (e.g. in completion payload or a separate feedback call). That score can be subjective to resource use: the agent can down-score workers that over-declared or misused resources. By feeding completion score into reputation, over-declaration is discouraged without making resources an eligibility gate.
Disclosure & privacy model (v0)
Three disclosure levels
-
Public listing
- Full job description visible to eligible bidders.
-
Redacted listing
- Public: high-level summary + constraints + budget/SLA.
- Full payload shared only with selected winner (or with bidders who stake/agree to NDA-like terms).
-
Private listing
- Only pre-approved workers can view or bid.
Redaction approach (practical)
- Requester provides:
public_summarysensitive_payload(shared only after selection)
- Winner receives full payload only after committing to execute (and optionally posting collateral).
Reputation (v0): Vector, not scalar
Reputation is tracked as a vector; requesters may combine into a scalar policy.
Suggested per-worker metrics:
- reliability: completion rate, cancellation rate
- audit_pass_rate: fraction of audits passed (weighted)
- latency: SLA adherence / average time-to-complete
- safety: policy violations, privacy incidents
- dispute_rate: fraction of jobs disputed/overturned
- completion_score (or requester_rating): score the requester/agent gives at job completion (optional in v0). Can be subjective and can reflect resource use (e.g. over-declaration).
Marketplace stores raw stats; requesters can compute a score like:
score = w1*reliability + w2*audit_pass_rate - w3*dispute_rate - w4*safety_incidents + w5*completion_score
The completion_score term can incorporate resource-use feedback (e.g. down-scoring workers that over-declared resources).
Quality assurance: “rare but serious” audits
Philosophy
Most jobs run once. A small fraction are audited deeply. Audits are rare, but failing an audit is expensive enough to deter cheating.
Audit triggers
Audits occur when:
- Random sampling (e.g., 1–5% of jobs)
- Risk-based triggers, e.g.:
- new worker / low history
- high-value budget
- privacy-sensitive jobs
- worker had recent failures
- requester flags suspicion
- marketplace anomaly detection
Audit methods (in increasing cost)
-
Deterministic verification
- Unit tests, schema validation, invariants, replayable checks.
-
Peer review
- Independent agent evaluates output against a rubric.
-
Redundant execution
- Send the same job to 1–2 additional workers; compare outputs.
- Used for: disputes, high-value jobs, high-risk kinds.
Audit funding
- Requester can pay for “extra assurance”.
- Marketplace can fund sampling audits via a small fee skim.
Penalties & rewards
If audited and PASS
- Reputation boost (especially audit_pass_rate)
- Optional bonus payout (small, from marketplace fee pool)
If audited and FAIL
Severity depends on failure type:
- Minor quality miss: rep down + warning.
- Incorrect result: rep down, partial refund, increased audit rate.
- Fraud / malicious: heavy penalty, ban, collateral slash (if used).
- Privacy leak: immediate ban + severe penalty.
Important: penalties should be large enough that expected value of cheating is negative.
Disputes & escalation (v0)
Disputes can be raised by:
- requester
- marketplace (audit finding)
Resolution path:
- deterministic checks (if available)
- peer review
- redundant execution
- (later) arbitration committee / DAO / on-chain dispute contract
Compatibility with future decentralization
Near-term target
- Off-chain matching & bidding
- Optional on-chain settlement (payment rails), but NOT required.
Later upgrades
- Commit–reveal bids
- Reputation as signed attestations
- Multiple marketplaces reading the same job board
- Collateralized worker identities
- On-chain dispute resolution for a subset of jobs
Open questions
- Collateral / staking requirements: per job, per worker, or optional?
- Standard rubrics per
kind: what’s the minimal acceptance criteria spec? - How to avoid requester abuse (false disputes)?
- Privacy guarantees for redacted listings as the network grows.