Use cases/Lanes Link/Give agents scoped access, with an audit trail

Give agents scoped access, with an audit trail

Every capability is denied until you allow it. Let an agent search your mail without letting it send, and get one append-only audit record per call, refusals included.

The usual way to give an agent access to your email is to give it your email. OAuth scopes are coarse, the consent screen is a one-time decision, and after that the only thing standing between "read my inbox" and "send as me" is a sentence in a system prompt asking the model not to. That is a policy the model is invited to respect, not one anything enforces.

Lanes Link puts the boundary in the runtime instead. Every capability is denied until you allow it, and policy only ever tightens as a request travels inward. gmail.search = allow and gmail.send = deny are decisions the endpoint enforces before dispatching anything, whatever the model was told or convinced to do.

How Lanes Link does it

  • Deny by default. Nothing is reachable until you allow it. Widening access is a decision you make deliberately, rather than the state you land in by accepting a consent screen.
  • Per capability, not per account. Search and send are separate capabilities on the same connection, so read-only access to a mailbox is a thing you can actually express.
  • Policy tightens inward, never loosens. A request cannot pick up permissions on its way through the endpoint, so a broad grant at one layer is not a way around a narrow one further in.
  • One audit event per invocation. Append-only, with per-provider redaction that keeps the identifiers and withholds your content, so the log tells you what happened without becoming a second copy of your mail.
  • Refusals are recorded too. lanes link audit tail --denied-only prints just those, which is the fastest way to see an agent repeatedly trying something you did not grant.
  • Tamper-evident. Records are hash-chained per run, and lanes link audit verify walks every chain.
  • No database to secure. State and the audit log are objects in a blob store: a directory on your machine locally, a bucket when deployed.

The workflow

Grant narrowly and widen when something is actually blocked. A refused call is the permission system working, not an obstacle to route around: a well-briefed agent reports what it was refused and lets you decide whether to open it, rather than looking for another path to the same data.

Then read the log. Because every invocation produces exactly one record, "what did that agent actually touch last night" is a question with an answer, and so is "what did it try to touch." That second one is usually the more interesting log, and it is the one most setups do not keep at all.

Set it up

Install it, start the endpoint, and connect an account:

console
$ bun install -g @lanes-sh/link
$ lanes link profile add personal --default
$ lanes link start
ok    serving http://127.0.0.1:7337/mcp
      profiles: personal
$ lanes link connect gmail

Then:

  1. Allow only what the work needs. Leave everything else denied. Read access is often the whole job.
  2. Register the endpoint. lanes link mcp add installs a skill that tells the agent to surface refusals to you rather than working around them.
  3. Watch what gets refused. lanes link audit tail --denied-only shows the calls policy stopped, which is how you find both a scope that is too tight and an agent doing more than you expected.
  4. Verify the chain. lanes link audit verify walks every hash chain when you want proof the log has not been edited.
Scopes at the provider are still worth setting, and you should. They are just too coarse to be the only boundary: Gmail's read and send scopes are the granularity you get, and "this agent, this week, search only" is not something the consent screen can express.

Further reading

Browse the source at lanes-sh/link, Apache-2.0, or read the announcement.