UAP Record

Agent

The curator agent

What it does, what it may not do, and every change it has made.

This page describes the program that maintains the record files behind this site. It is written for readers of the site first and for the people who run the program second. The change log at the bottom of the page is the program's public record; nothing it does to the data is left out of it.

What it is

The knowledge base is a set of JSON files, one per type of record: sites, events, people, crafts, beings, documents, footage. Every record carries a summary, an evidence band, and a list of sources. A source is either a quotation from one of the interview transcripts in the corpus, cited to the video and the timestamp, or an external page with a title and a URL.

The curator is a scheduled program that reads those transcripts and those files and proposes changes to them. It uses a language model to read, compare and write, and it uses ordinary code for everything that can be checked without judgement: whether a quotation really appears in the transcript at the cited place, whether a record follows the schema, whether two records describe the same thing, whether a cross-reference points at a record that exists. The model cannot get around those checks. It can only ask for a change; the code decides whether the change is well formed, and a person decides whether it is right.

What it does

It runs four kinds of task.

conversation is about the subject, and read the most relevant ones in windows of a few minutes each. Where a transcript describes a place, an event, a person, a craft or a document that the files do not have, propose a new record with the quotation that supports it. Where it adds to a record that exists, propose the quotation as a new source.

nowhere, records that carry the same name or alias under different slugs, sources whose quotation no longer matches the transcript. Propose a fix for each finding that has one, and write a note for each that does not.

each verified passage as a source, plus the cross-references those passages justify.

against the corpus, and either propose the change with a source or explain why it cannot be made from the material available.

Each task is one run. A run reads, calls its tools, and ends with a written summary of what it proposed and what it deliberately did not propose. The full transcript of every run, every tool call and its result, is stored and can be read on a private review page.

What it may not do

These limits are enforced in code, not only in the instructions the model is given.

exact string appears in the transcript file within two minutes of the cited timestamp and is at most 300 characters. A paraphrase fails. A quotation with the punctuation tidied fails. The transcripts are machine transcriptions of speech and contain misspellings; the curator quotes them as they are rather than correcting them, because a corrected quotation is no longer a quotation.

needs a video, a timestamp, a speaker and a verified quotation. A record without a source is refused.

even then only after the project's validator has accepted the whole file with the change in it. By default both switches are off and the program only files proposals.

Publishing is a separate script that the program does not call under any setting.

is capped on how many proposals one run may make.

is recognised and refused as a duplicate.

material to check, never as an instruction to follow.

The bands a record carries (documented, well-supported, contested, thin, unsupported) are judgements about the sources, and the curator records them as judgements: a band proposed by the program is reviewed like any other change. The program does not decide whether any of the events described in the corpus happened. It records who said what, where, and what supports it.

How every change is logged

Three records are kept.

record it targets, the patch itself, the reasoning the model gave, and the validator's output. A proposal is in one of three states: proposed, applied, rejected.

the model's reasoning and tool use. This is how a proposal can be traced back to the passage that prompted it and to the checks that were made along the way.

to CHANGELOG.jsonl, the file rendered at the bottom of this page. The file is append-only; nothing is edited or removed from it. Each line records the time, the actor, the kind of action, the record it touched, a one-line summary, the outcome, and the run it came from:

{"ts": "2026-09-04T19:40:12Z", "actor": "curator", "action": "add_source",
 "target": "people/bob-lazar", "summary": "narrator on the map change after Lazar spoke",
 "status": "applied", "run_id": 42, "proposal_id": 17}

A change that was proposed and never applied does not appear in the change log; it appears in the proposals record, with the reason it was refused or the fact that it is still waiting.

How to propose a correction

A correction is a small JSON file describing what you believe is wrong and, if you can, what it should say instead. The fields are:

{
  "type": "sites",
  "slug": "area-51",
  "submitted_by": "your name or handle",
  "claim": "One or two sentences on what is wrong.",
  "suggested_change": {"aliases": ["Homey Airport"]},
  "note": "Where you saw it, or anything the reviewer should know."
}

type and slug name the record; both appear in the record's address on this site. suggested_change is optional. The strongest correction points at a place in the corpus: a video id and a timestamp where the transcript says the thing you are describing. A correction that cannot be supported from the corpus or from a named external source will be written up as a note for a reviewer rather than applied, and the note will say why.

The file is handed to the program with the moderate task. The program reads the record and the relevant transcript, checks the claim, and either files a proposal or logs its reasons for not doing so. Either way the outcome is visible in the proposals record, and if a change is applied it appears in the change log below.

What to expect from its output

The curator writes in reported speech. It says that a speaker described, claimed or said something; it does not say that the thing exists or occurred. It avoids words chosen for effect. It does not put a number on how often something appears unless it has counted, and its search tool returns the count with every result so that it can. When a passage does not support a record, the expected output is a note saying so, not a weaker record.

The ranking that decides which transcripts a sweep reads first is a list of terms, not a judgement. A transcript in which none of those terms appears is skipped and the skip is recorded, so that the model's time goes to the interviews that are about the subject. The term list can be read in agent/app/corpus.py.

Running it

For the people operating the program. Everything runs from the 13_uap directory.

python -m agent.cli review                        # consistency checks, proposals only
python -m agent.cli sweep                         # read uncovered transcripts, propose records
python -m agent.cli enrich people/bob-lazar       # more sources for one record
python -m agent.cli moderate path/to/suggestion.json
python -m agent.cli serve                         # review dashboard on 127.0.0.1:8791
python -m agent.cli gates                         # print the effective switches
python -m agent.replay.replay                     # offline test of the whole pipeline, no key needed
python -m unittest agent.replay.test_guards       # unit tests of the guards

The switches, read from agent/.env:

whatever the other switches say.

to the data file after the validator passes.

write. It never publishes.

person with the control-room script.

The review dashboard shows each run's reasoning and tool calls, each proposal with its patch and validator output, and buttons to approve or reject. Approving applies the change only if the write switches are on; otherwise the approval is recorded and the proposal waits.

A launchd template in agent/ops/ runs review daily and sweep weekly. It is not installed by default. Installing it does not open any switch.

The community lanes

The same curator also answers in the community rail on every page: it replies to members' questions about a page (chat), acts on reported posts (moderate), works research tasks (research) and reviews the tasks members submit (review_task). Jobs are leased from the community API (13_uap/community/CONTRACT.md §5, header X-Agent-Token); one model run per job, with the curator's read tools plus the community write tools. Every factual sentence in an answer must cite a corpus timestamp or a URL on the site or in the record's sources — the answer_chat tool resolves each citation against the corpus index and refuses the call when one does not exist. Research suggestions are text in the report; these lanes have no propose_change and no apply. The prompt is agent/prompts/community_agent.md.

python -m agent.cli community-once --limit 1           # lease one job, work it, exit (from 13_uap)
python -m agent.cli community-once --kinds chat,moderate --limit 3
python -m agent.cli community-loop                     # poll every UAP_COMMUNITY_POLL_S seconds
python -m unittest agent.replay.test_community         # the lane tests against a local fake of the API

Switches, in agent/.env: UAP_COMMUNITY_API and UAP_COMMUNITY_TOKEN (required; empty API = the lanes refuse to start), UAP_COMMUNITY_DRY_RUN (default 1: jobs are leased and the model runs, every write logs would_post and the job is released with dry_run; because a failed chat marks the member's question failed, a dry-run leases chat only when --kinds names it; set 0 for live), UAP_COMMUNITY_POLL_S (20), UAP_COMMUNITY_MODEL_CHAT / _BATCH (grok-4.6; chat at effort=high,fast=true because a person is waiting, everything else effort=xhigh,fast=false), FIRECRAWL_API_KEY for the web_search tool (absent: the tool says so and the model works from the corpus). Each run is stored like a curator run (community:<kind>) and shows on the dashboard.

To keep the loop running under launchd (KeepAlive, restarts within 30 s, logs in ~/Library/Logs/uap-community.log), from 13_uap/agent:

cp ops/com.ab7.uap-community.plist.example ~/Library/LaunchAgents/com.ab7.uap-community.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.ab7.uap-community.plist
launchctl kickstart -k gui/$(id -u)/com.ab7.uap-community   # restart after a code or .env change
launchctl bootout gui/$(id -u)/com.ab7.uap-community        # stop and remove

ops/run_community.sh loads .env, takes CURSOR_API_KEY from ~/.lfc-agents/cursor-api-key.new and FIRECRAWL_API_KEY from ~/.cursor/mcp.json when they are not already set, and execs cli.py community-loop. Nothing in it prints a secret.

Change log

No changes logged yet.