---
title: "The useful part of a vault portal was admitting the ai should read, not write"
canonical: https://dxdev.com/blog/2026-05-05_vault-portal-read-before-write/
datePublished: 2026-05-05
---
On May 5, I shipped `/v/<path>?k=<key>` for human reads and `/v.md` for AI fetchers, and deleted half the autonomous-write design I had been carrying around for a month. The portal got smaller and immediately got useful.

The previous version of this work was a write-first portal. Agents would post into a quarantine table, I would promote what I wanted, and the substrate was going to be bidirectional from day one. That was wrong. I had skipped the part where the read path actually works, in favor of the part where the AI looks autonomous.

## the smallest thing that mattered

The shape that shipped is narrow. One URL pattern, one capability key per path, two render modes.

`/v/<path>?k=<key>` renders HTML for a human opening a share link. `/v.md` renders the raw markdown for an agent fetcher that does not want to parse a page. The key is opaque, scoped to a single concrete file, and revocable from the Share dialog without touching the underlying vault.

That is the entire surface area. No write endpoint. No agent identity. No promotion queue. The portal does one job: turn a vault path into a fetchable URL that I can hand to any AI that knows how to do a GET.

## the access story has to be honest before anything else matters

The reason I had been chasing autonomy was that the read story felt boring. Anybody can serve a markdown file. The interesting design is the loop where agents close their own tickets, post into queues, propose patches. That is the demo.

But the access story underneath was hand-wavy. Who can read what. How keys get revoked. What happens when a share leaks. Whether Cloudflare or WAF actually sees the traffic. I had answers for none of these, and I was about to build write semantics on top.

The reversal was to stop and build the Share dialog, the key allowlist, the WAF rules, and the audit trail first. None of that is glamorous. All of it is load-bearing. A private vault with an unclear access model is worse than no portal at all, because you stop noticing what you have exposed.

## what each agent actually did

Claude fetched `/v.md` URLs on the first try. Manus did too. GPT browse refused to fetch from a fresh subdomain, which I initially read as a philosophical objection and then realized was just an integration constraint, the kind every tool has. I wrote it down and moved on. It is not a portal problem. It is a "GPT's browse tool is conservative about new hosts" problem, and the fix is reputation accrual, not architecture.

The agents that worked, worked immediately. That is the test I care about. A read substrate that requires custom integration per agent is not a substrate. It is a vendor lock-in in a trench coat.

## sessions are not the surface

The same week, I rebuilt the HoldThought dashboard around Area, Epic, and Task, with sessions hanging off the side. The first version had centered sessions. The new version treats them as exhaust. Same lesson, different layer: model the thing you are trying to find, not the thing the machine produces while finding it.

Renaming `MT-YYMMDD-NN` and `ME-YYMMDD-NN` into bare integer IDs was the kind of migration nobody writes about because it does not feel like product work. Nineteen vault directories renamed, three ID collisions resolved by hand. But the dashboard only started making sense after the IDs stopped fighting the hierarchy. The portal and the dashboard are the same shape: get the substrate honest, then layer behavior on top.

## the principle

A lot of AI tooling goes wrong because the design starts with agency before a clean transport layer exists. You can tell, because the demo is impressive and the day-to-day is brittle. Agents post into queues that nobody promotes from. Permissions are vague enough that nobody trusts them. Every new agent needs a new integration because the substrate was never actually substrate.

The first useful AI portal is a narrow, auditable read path. The write side comes later, on top of the same key model, after the read side has earned its keep.
