Core concepts¶
Six ideas carry the whole platform: sessions and forks, executions, findings and severity, workspaces and projects, audits and reports, and attestations. Everything else is a detail of one of them.
Sessions and forks¶
A fork is a private copy of a real chain, pinned to a block. It reads through to an upstream node for state it does not have, and it never writes anything back. A session is your handle on one fork: it holds the fork, the contracts in scope, the accounts, and the history of what you have run.
Opening a session is a real boot — the fork is created for you and the target
contract is loaded and analysed. You get back a session_id, and the session
stays with you until you close it.
Two accounts matter by convention. The auditor is the account you send from; the other side of the scenario is whatever the target needs — a pool, a router, a token holder.
Balance reads and the transaction sender accept a small set of aliases in place
of raw hex: auditor (you), me (equivalent), and target (the contract under
analysis). Everything else must be a hex address. "Counterparty" is how these docs
talk about the other side of a scenario — it is not an alias the API accepts, and
sending it is rejected at the front door with 400 validation_failed.
Isolated and stateful sends¶
The single most important behaviour to understand is how a send treats state.
| Mode | What happens | Use it for |
|---|---|---|
| Isolated (default) | Each transaction runs from the same base state, is measured, then rolled back | Comparing variants — twenty attempts, all from identical conditions |
Stateful (persist: true) |
Each transaction commits, and the next one starts from the result | Multi-step reproductions where step 3 depends on step 2 |
A stateful sequence is how a real finding gets demonstrated: fund an account, call the setup function, then call the one that breaks. The mined block climbs as you go.
Snapshots¶
A snapshot is a named point you can return to. Take one before a risky sequence
and restore it afterwards, and you can re-run the same reproduction from the same
starting conditions as many times as you need — without rebuilding the fork.
Restoring is a mutating call, so it needs an
Idempotency-Key.
See Sessions and forks for the endpoints.
Executions¶
Every transaction you send against a fork produces an execution, identified
as exec_…. It is a durable resource, not a log line: it is written as
accepted before the transaction fires, and moved to confirmed or failed
after. A send that dies mid-flight is therefore visible as accepted, never
silently absent.
Each execution carries what it did — gas, value deltas, the storage slots it touched with before and after values, the return data, the revert reason if it reverted — and it is attributed to a user, a workspace and a project. That is what makes a reproduction citable weeks later rather than a screenshot.
Executions and their traces are listed under Execution.
Findings and severity¶
A finding is a claim about a contract that you can support. It has a title, a description, a location, and a severity:
| Severity | Meaning |
|---|---|
critical |
Direct loss of funds or complete loss of control |
high |
Serious impact, or loss under conditions an outsider can create |
medium |
Real impact under narrower conditions |
low |
Limited impact, or requires an unlikely precondition |
info |
No direct impact; hygiene, clarity or defence in depth |
Findings arrive from three directions and land in the same ledger: the detector sweep over a contract's bytecode, the analysis endpoints that probe a specific class of problem, and you — filing what you found by hand. Findings attach to an audit inside a workspace, and they can be exported as SARIF for a code-scanning pipeline.
The important discipline: a finding is reproducible when there is an execution on a fork that demonstrates it. That link is what an attestation later seals.
Workspaces, projects and contracts¶
Tenancy is a chain of containers, widest first:
organization
└── team
└── workspace tenancy + membership boundary
├── project one engagement, one codebase, one scope
│ └── contracts the inventory under review
├── audits the work, with its findings
├── reports what you publish
└── activity an append-only trail of what happened
A workspace is what you are billed to, invited into, and audited within. A project is a single engagement inside it. The contract inventory is the set of addresses in scope, so "what did we actually review" is a stored fact rather than an argument.
Both IDEs file into the same structure. An execution from the Auditing IDE and a merge request from the Contract IDE land in one workspace's activity trail, which is what makes the record reconstructable.
Endpoints: Workspaces, Projects, Contract index, Activity.
Two things named 'reports'
A workspace's reports are documents you author and share. A project also has a reports view, which is the same documents filtered to that engagement. They are one concept seen at two scopes, not two features.
Audits and reports¶
An audit is the unit of work: it collects findings, comments, acknowledgements and a status, and it can be resolved, archived or shared. A report is what leaves the building — a document produced from an audit, publishable behind a share link with a controlled lifetime.
Sharing is deliberate and revocable. A share link is its own resource; deleting it withdraws access without touching the report.
Endpoints: Audit index, Workspaces.
Attestations (Audit Passport)¶
An attestation is a signed, tamper-evident record that a specific audit reached a specific conclusion at a specific time. Attestations within a workspace are hash-chained — each one commits to the previous — so a record cannot be quietly removed or reordered after the fact.
They are signed with RS256, and the public keys are published as a JWKS. That means a third party — a client, an exchange, an insurer — can verify a passport you hand them without an account:
and then submit the passport itself. The request is the certificate exactly as it was issued — the server re-derives the hashes over what you send and checks the signature against the published key. It reads no tenant data and returns nothing but a verdict:
curl -X POST https://api.trilocore.ai/api/v1/public/attestations/verify \
-H "Content-Type: application/json" \
-d @passport.json
The verdict separates its reasons — whether the content is consistent, whether the hash chain is consistent, and whether the signature is valid — so a failure tells you which of the three broke.
What verification does and does not prove
A successful verification proves the attestation was issued by Trilocore and has not been edited since. It does not re-derive the audit, and it does not check the contract's current on-chain state — a contract can be upgraded the day after a valid passport is issued. Read a passport as "this audit happened, and this is exactly what it said", not as a live safety guarantee.
Endpoints: Public (unauthenticated) and the
attestation routes under Workspaces. Issuing an
attestation is a mutating call and requires an
Idempotency-Key.
How the API expresses all this¶
Every concept above is a resource with an identifier in the path, and the API is
uniform about it: creation returns 201 with a Location, a resource you cannot
see returns 404 rather than admitting it exists, and errors carry a stable
machine-readable code.
- API overview — base URL and the resource model
- Authentication — keys, sessions and CSRF
- Idempotency — which calls require a key, and what replay means
- Errors — the
codecatalogue - Rate limits — headers and quota