Puckai Single-Agent: basic example GitHub issue
- The scenario
- Conventions in this example
- Before — the worldlet sent to the agent
- After — the worldlet returned from the agent
- Things to notice
The umbrella question — a worked walkthrough of a single-agent session.
vibecode
{"vibecode": { "doc": "Puckai_single_agent_basic_example", "role": "worked example showing a complete single-agent Puckai session — the basic case, with one agent answering a boolean assertion based on an external lookup. Companion to the single-agent spec at ../index.md.", "audience": ["humans learning Puckai by example", "AI agents needing a concrete reference for the single-agent flow"], "scenario": "A caller (a human in this example, but could equally be a program) poses the assertion 'An umbrella is necessary for walking in Seattle, Washington at 10am tomorrow.' The agent consults the National Weather Service and returns true with a report.", "shared_spec": "../index.md" }}
This is the basic example for single-agent mode — a complete worked session showing every record a real run produces. Use it as a reference for the shape of a single-agent Puckai exchange; the spec describing the mode itself lives at ../index.md.
The scenario GitHub issue
A caller poses an assertion for evaluation: "An umbrella is necessary for walking in Seattle, Washington at 10am tomorrow." In this example the caller happens to be a person planning their morning, but it could equally be an automated program running a routine check, a CI pipeline gating a deploy on a weather condition, or another agent handing the question off. Puckai doesn't assume a human at either end — the format is just as valid for entirely program-to-program use.
The caller wants a boolean decision (encoded as true / false), with the agent consulting whatever external data it needs along the way.
The chosen single agent — a fictional "Weather Advisor" running Claude Opus 4.7 — receives the worldlet, registers itself, frames the question more precisely, consults the National Weather Service forecast API, decides true with 0.85 confidence, writes a report explaining the reasoning, and signs off.
Why an assertion rather than a question? Pairing expects: "boolean" with an assertion makes the answer trivially interpretable: true means the assertion holds, false means it doesn't. No mapping between yes/no and the truth-value is needed — the assertion itself defines what each truth-value means.
Conventions in this example GitHub issue
Record keys. Real worldlets typically use UUID v4 keys. This example uses short single-letter strings (a, b, ...) for readability. Mikobase only requires keys to be unique strings; UUIDs are a recommended convention, not a hard rule.
Record shape. Records use the simple form: class at the top level alongside the data fields. No {bucket, stack} wrapper — that form is reserved for records needing multi-platter expression, which this example doesn't.
Worldlet vs delta on the return. The example shows the full worldlet coming back (input records preserved plus the new ones the agent added). A real implementation could just return the delta — the receiver already has the originals — but the full form is more pedagogically useful.
Before — the worldlet sent to the agent GitHub issue
before.json — what the caller sends. Two records (a session and an issue), plus a top-level vibecode block.
The top-level vibecode carries agent guidance — instructions to the agent that aren't part of the caller's question. In this example: a tone preference ("factual, minimal hedging") and a directive to post a puck.uno/ai/puckai/frame record when the question is ambiguous. The boolean cutoff (confidence_floor: 0.6) lives on the issue record itself.
The records:
a(session) — pure container.status: "open", no agents yet (the agent will populateagentswhen it registers itself). No agenda, no expects — those live on the issue.c(issue) —agendacarries the assertion,expects: "boolean"shapes the answer,confidence_floor: 0.6sets the boolean cutoff,report: trueopts the issue in for a human-readable report alongside the bare decision.status: "open". The issue's ownvibecodeblock adds context — when the question was asked, what the user is planning.
The caller doesn't include an agent record. The agent is reached at its URL (out of band) and registers itself when it sees the worldlet. The session and the issue are deliberately separate records: a session is a container; questions are issues; one session can carry one issue or many.
{
"format": "worldlet/1.0",
"uuid": "d29390b6-779b-47b5-995a-e96866dc0150",
"comment": "The worldlet SENT TO the agent. Contains the session record (the container) and one issue record carrying the question to be answered. The agent is reached at its URL (out of band); when it receives the worldlet, it registers itself by adding its own puck.uno/ai/agent record and updating the session's agents hash. The issue has `report: true`, so the agent will write a narrative report in addition to the bare decision. Records use the simple form (class at top alongside data fields). Record keys would usually be UUIDs in a real worldlet; short single-letter strings are used here for legibility.",
"vibecode": {
"agent_guidance": {
"tone": "factual, minimal hedging",
"on_ambiguity": "post a puck.uno/ai/puckai/frame record stating your interpretation before deciding"
}
},
"records": {
"a": {
"class": "puck.uno/ai/puckai/session",
"status": "open",
"created_at": "2026-06-02T18:30:00.000Z"
},
"c": {
"class": "puck.uno/ai/puckai/issue",
"session": "a",
"agenda": "An umbrella is necessary for walking in Seattle, Washington at 10am tomorrow.",
"expects": "boolean",
"confidence_floor": 0.6,
"report": true,
"status": "open",
"vibecode": {
"context": "Asked at the end of the work day; user has a 20-minute walk planned at 10am the next morning."
},
"created_at": "2026-06-02T18:30:00.000Z"
}
}
}
After — the worldlet returned from the agent GitHub issue
after.json — the complete final worldlet. The session (a) and issue (c) from before, updated, plus the records the agent added — starting with its own agent record. The top-level vibecode from before.json is preserved.
a(session) — status flipped to"resolved".agentshash now populated withb(the registered agent) as originator.c(issue) — status flipped to"resolved". Everything else (agenda, expects, confidence_floor, thereport: trueopt-in, thevibecodecontext) carries through frombefore.json.b(agent) — the Weather Advisor's identity. The agent created this record when it received the worldlet — that's how it registers itself in the session.h(frame) — authored by agentb(theagentfield on the frame record points there), withissue: "c"scoping it to the issue. The agent's restatement of the agenda: "Will the precipitation in Seattle, Washington on 2026-06-03 at 10:00 local time be heavy enough that a typical walker would benefit from carrying a rain umbrella?" The frame's ownvibecodeblock lists the disambiguations the agent made (e.g., "umbrella" read as "rain umbrella," not a protest sign). Posting this is what theon_ambiguityguidance asked for.d(consultation) — the agent consulted the National Weather Service forecast endpoint. The record captures the URL, query, response text, and timestamp; it lives separately from the report so the audit trail keeps consultation provenance distinct from the agent's narrative.e(decision) —issue: "c"scopes the decision to the issue.body: true(the assertion holds), withbased_on: "h"referencing the frame. The chain is issuec.agenda → frameh→ decisione: the original assertion, the agent's interpretation, and the verdict on that interpretation. Confidence0.85, comfortably above the issue'sconfidence_floorof0.6.f(report) — written becausec.reportwastrue.issue: "c"scopes it;decision: "e"points to the decision it describes. Carries the summary, the markdown reasoning, the next-steps note.open_itemsis empty since the consultation gave a clear forecast. Confidence is not duplicated on the report — the decision is the canonical home for the number; the markdown discusses it in narrative form.g(sign_off) — the agent disconnects.
{
"format": "worldlet/1.0",
"uuid": "d29390b6-779b-47b5-995a-e96866dc0150",
"comment": "The worldlet RETURNED FROM the agent — the complete final state of the single-agent session resolving the umbrella question. The agent (Weather Advisor) received the initial worldlet (see before.json), registered itself, framed the issue, consulted the National Weather Service, rendered a decision (body: true with confidence 0.85), wrote a report (because issue.report was true), and signed off. The session record is a pure container; the question lives on the issue record. Records use the simple form (class at top level alongside data fields).",
"vibecode": {
"agent_guidance": {
"tone": "factual, minimal hedging",
"on_ambiguity": "post a puck.uno/ai/puckai/frame record stating your interpretation before deciding"
}
},
"records": {
"a": {
"class": "puck.uno/ai/puckai/session",
"agents": {
"b": {
"role": "originator"
}
},
"status": "resolved",
"created_at": "2026-06-02T18:30:00.000Z"
},
"c": {
"class": "puck.uno/ai/puckai/issue",
"session": "a",
"agenda": "An umbrella is necessary for walking in Seattle, Washington at 10am tomorrow.",
"expects": "boolean",
"confidence_floor": 0.6,
"report": true,
"status": "resolved",
"vibecode": {
"context": "Asked at the end of the work day; user has a 20-minute walk planned at 10am the next morning."
},
"created_at": "2026-06-02T18:30:00.000Z"
},
"b": {
"class": "puck.uno/ai/agent",
"name": "Weather Advisor",
"url": "https://example.com/weather-advisor",
"owner": "advisor.example.com",
"model": "claude-opus-4-7",
"registered_at": "2026-06-02T18:30:00.000Z"
},
"h": {
"class": "puck.uno/ai/puckai/frame",
"session": "a",
"body": "Will the precipitation in Seattle, Washington on 2026-06-03 at 10:00 local time be heavy enough that a typical walker would benefit from carrying a rain umbrella?",
"vibecode": {
"disambiguations": [
"'umbrella' read as 'rain umbrella' (not a protest sign, not a beach umbrella)",
"'necessary' read as 'would benefit from' (not strictly required for survival)",
"'tomorrow at 10am' read as the calendar day after the session timestamp, in Seattle local time"
]
},
"created_at": "2026-06-02T18:30:30.000Z",
"agent": "b",
"issue": "c"
},
"d": {
"class": "puck.uno/ai/puckai/consultation",
"session": "a",
"source": "https://api.weather.gov/gridpoints/SEW/124,67/forecast",
"kind": "api",
"query": {
"endpoint": "forecast",
"location": "Seattle, WA",
"grid": "SEW/124,67"
},
"response": "Tuesday 2026-06-03: Showers likely, mainly between 9am and 1pm. Cloudy, with a high near 63. Southwest wind 5 to 10 mph. Chance of precipitation is 60%.",
"timestamp": "2026-06-02T18:30:45.000Z",
"agent": "b"
},
"e": {
"class": "puck.uno/ai/puckai/decision",
"session": "a",
"issue": "c",
"body": true,
"based_on": "h",
"agreed_by": [
"b"
],
"confidence": 0.85
},
"f": {
"class": "puck.uno/ai/puckai/report",
"session": "a",
"issue": "c",
"decision": "e",
"summary": "The assertion holds — true. The NWS forecast for Seattle on 2026-06-03 puts showers between 9am and 1pm with a 60% chance of precipitation, so 10am is squarely in the rainy window.",
"open_items": [],
"next_steps": [
"Re-check the forecast closer to departure if the weather feels uncertain — forecasts update as the day progresses."
],
"markdown": "# An umbrella is necessary for walking in Seattle at 10am tomorrow.\n\n**Assertion: true** (confidence 0.85; see decision `e`).\n\n## Frame\n\nI interpreted the question as: *Will the precipitation in Seattle, Washington on 2026-06-03 at 10:00 local time be heavy enough that a typical walker would benefit from carrying a rain umbrella?* See frame record `h` for the full disambiguation.\n\n## Reasoning\n\nI consulted the National Weather Service forecast for Seattle (grid SEW/124,67) and got back: *Tuesday 2026-06-03: Showers likely, mainly between 9am and 1pm. Cloudy, with a high near 63. Southwest wind 5 to 10 mph. Chance of precipitation is 60%.* See the consultation record (key `d`) for the raw response.\n\nThe 10am hour falls inside the forecast window of likely showers (9am–1pm). A 60% chance of precipitation is high enough that the asymmetric cost of being wrong matters: the cost of carrying an umbrella you don't use is small (a minor inconvenience), while the cost of being caught walking in morning rain is larger (getting wet on the way to wherever the user is going).\n\nAt that probability and during that specific window, an umbrella is necessary.\n\n## Bottom line\n\nThe assertion is true. Carry the umbrella."
},
"g": {
"class": "puck.uno/ai/puckai/sign_off",
"session": "a",
"body": "Decision rendered. Returning the worldlet.",
"agent": "b"
}
}
}
Things to notice GitHub issue
- The session is a container; the issue carries the question. Read the session record (
a) and you learn who's participating and what state the session is in. Read the issue record (c) and you learn what's being asked. The split scales naturally — a session with three issues would have three issue records, each with its own frame/decision/(optional) report chain. - The per-issue chain is the audit trail. Reading the worldlet, you can trace from the issue's
agendathrough the agent'sframe(recordh) to thedecision(recorde), and the optionalreport(recordf) writes up the whole story for a human reader. Each link names what it references; nothing is implicit. - The consultation is a first-class record, not narrative prose. If a future auditor wonders where the agent got its information, they can find the API endpoint, query, and response text in record
d— separately from whatever the agent decided to say about it in the markdown report. Provenance and narrative are kept distinct. - Confidence lives on the decision, not the report. Record
ecarries the canonicalconfidence: 0.85. The report (f) mentions it in narrative form but doesn't duplicate the field — there's one number, one place. When the report is absent (as it would be ifc.reportwerefalse), the decision still carries confidence on its own. - The report is opt-in. This issue set
report: true, so recordfexists. Withreport: false(or the field omitted), recordsa,b,c,h,d,e,gwould still be present — the bare decision would be the deliverable, no narrative writeup. Default is no report; opt in when a human needs to read what happened. - The issue's
vibecodecontext survives end-to-end. The "user has a 20-minute walk planned" note the caller attached is still there in the final worldlet — vibecode hints travel with the records they sit on, not just on the input. - No conversation classes appear. No proposals, objections, refinements, questions, responses, evidence records, acceptances, impasses, or stances — those belong to conversation mode. Single-agent uses only the shared class library.