Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/logicsrc-web/contract/spec-discovery.contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ vi.mock("../src/lib/supabase", () => ({ publicClient: () => { throw new Error("o

describe.each([
{ slug: "openagent", name: "OpenAgent", family: "people" },
{ slug: "openpersona", name: "OpenPersona.md", family: "people" },
{ slug: "openskill", name: "OpenSkill", family: "people" },
{ slug: "openabtest", name: "OpenABTest", family: "process" },
{ slug: "openfleet", name: "OpenFleet", family: "process" },
Expand Down
23 changes: 23 additions & 0 deletions apps/logicsrc-web/public/examples/openpersona.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Research agent

- **OpenAgent**: https://example.com/agents/research.json
- **DID**: research.coinpay
- **Disclosure**: AI agent operated by Example Research

I find primary sources and prepare cited research briefs. I am concise, careful
about uncertainty and clear about which facts I verified.

## Voice

- **Description**: Clear, steady English with a measured pace.
- **Provider**: Example TTS service
- **Voice ID**: example-voice-id

## Conversation

- **Style**: Direct, calm and specific.
- **Turn-taking**: Answer direct questions; wait while another person is speaking.

## Boundaries

- **Limits**: Do not present an unverified claim as fact.
2 changes: 2 additions & 0 deletions apps/logicsrc-web/src/app/openagent/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const metadata: Metadata = specMetadata(

const LINKS = [
["OpenProfile.md", "/openprofile", "The identity, accounts and topics people read. Link the JSON descriptor from the same profile page."],
["OpenPersona.md", "/openpersona", "The agent's public role, spoken voice and conversational style, linked from its profile page."],
["OpenFleet", "/openfleet", "The running sessions and their human sysop. A launcher maps one agent profile to many fleet members."],
["OpenRental", "/docs/openrental", "Agent listings and explicit rental offers. An openagent member points at this profile and matches its did."],
["OpenAccess", "/openaccess", "The delegated grant. Requested permissions in a profile do not grant access."],
Expand All @@ -29,6 +30,7 @@ export default function OpenAgentPage() {
</div>
<p>A directory, a job board and a launcher can read the same JSON profile. The agent keeps its identity when its hosting or engine changes, and each running session can be tracked separately through OpenFleet.</p>
<p>The format is the existing <code style={mono}>logicsrc.agent</code> contract. Its schema and offline validator already ship in LogicSRC; this publication adds discovery conventions and explains how the profile fits the other specifications.</p>
<p>Describe an agent's public persona in a separate <Link href="/openpersona">OpenPersona.md</Link> file. The OpenAgent schema stays unchanged; link the companion from the same profile page and bind it back to this JSON descriptor.</p>
<p><Link className="button-primary" href="/docs/openagent">Read the specification</Link>{" "}<a href="/examples/openagent.json">Download the example</a></p>
</section>

Expand Down
82 changes: 82 additions & 0 deletions apps/logicsrc-web/src/app/openpersona/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import Link from "next/link";
import type { Metadata } from "next";
import { specMetadata } from "@/lib/page-meta";
import { SiteShell } from "@/components/site-shell";
import { mono, pre, table, td } from "../openontology/ui";

export const metadata: Metadata = specMetadata(
"/openpersona",
"OpenPersona.md is a public Markdown companion to OpenAgent for an agent's role, spoken voice and conversational style. It points back to one OpenAgent descriptor and does not contain permissions or executable prompts."
);

const EXAMPLE = `# RiotCoder

- **OpenAgent**: https://profullstack.com/agents/riotcoder.json
- **DID**: riotcoder.profullstack
- **Disclosure**: AI agent operated by Profullstack, Inc.

I build and ship software for the Profullstack fleet. I am direct, practical and
clear about what I know and what I have verified.

## Voice

- **Description**: Natural US English, concise and even-paced.
- **Provider**: ElevenLabs
- **Voice ID**: iP95p4xoKVk53GoZ742B

## Conversation

- **Style**: Direct, specific and conversational.
- **Turn-taking**: Answer when addressed; wait while another person is speaking.

## Boundaries

- **Limits**: Never claim work shipped or checked unless it happened.`;

const PIECES = [
["OpenAgent", "/openagent", "Identity, owner, skills and requested permissions. The persona points back to this JSON descriptor."],
["OpenProfile.md", "/openprofile", "Human-readable identity, accounts and topics. Link OpenPersona from the agent's profile page."],
["OpenFleet", "/openfleet", "A running session and the human sysop responsible for it."],
["OpenCreds", "/opencreds", "Credentials stay in a vault; OpenPersona publishes no secrets."],
];

export default function OpenPersonaPage() {
return (
<SiteShell active="OpenPersona.md">
<section className="band">
<div className="section-head">
<p className="eyebrow">People and agents · specification 0.1</p>
<h2>OpenPersona.md</h2>
<p>One Markdown file for an agent's public role, spoken voice and conversational style.</p>
</div>
<p>OpenPersona.md accompanies <Link href="/openagent">OpenAgent</Link>. It describes how an agent presents itself to people; OpenAgent keeps the agent's identity, owner, skills and requested permissions.</p>
<p>The persona names the exact OpenAgent descriptor it describes. A profile page links both files. OpenPersona is descriptive public content, not an executable system prompt, tool list or permission grant.</p>
<p><Link className="button-primary" href="/docs/openpersona">Read the specification</Link>{" "}<a href="/examples/openpersona.md">Download the Markdown example</a></p>
</section>

<section className="band">
<div className="section-head">
<h2>The file</h2>
<p>The OpenAgent field binds this persona to one JSON descriptor. Voice provider details are optional descriptive metadata.</p>
</div>
<pre style={pre}>{EXAMPLE}</pre>
</section>

<section className="band">
<div className="section-head"><h2>Publish and link</h2></div>
<p>Serve one agent's file at <code style={mono}>/.well-known/openpersona.md</code>, or serve it beside the agent page on a multi-agent host. The profile page links it with:</p>
<pre style={pre}>{'<link rel="openpersona" type="text/markdown" href="https://example.com/agents/research/openpersona.md">'}</pre>
<p>Keep OpenAgent's existing JSON schema unchanged. Its own profile page advertises both descriptors, and the persona points back to the OpenAgent URL.</p>
</section>

<section className="band">
<div className="section-head"><h2>How the pieces fit</h2></div>
<table style={table}>
<tbody>{PIECES.map(([name, href, description]) => (
<tr key={name}><td style={td}><Link href={href}>{name}</Link></td><td style={td}>{description}</td></tr>
))}</tbody>
</table>
</section>
</SiteShell>
);
}
4 changes: 4 additions & 0 deletions apps/logicsrc-web/src/app/openprofile/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ export default function OpenProfilePage(): ReactNode {
<Link href="/docs/openresume">OpenResume.md</Link>, what you have done, in the same
spirit; a profile links to a resume and a resume to a profile
</li>
<li>
<Link href="/openpersona">OpenPersona.md</Link>, an optional companion for an agent&apos;s
role, spoken voice and conversational style
</li>
<li>
<Link href="/docs/openjob">OpenJob</Link>, what the work is
</li>
Expand Down
1 change: 1 addition & 0 deletions apps/logicsrc-web/src/lib/specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const FAMILIES: Family[] = [
s("openprofile", "OpenProfile.md", "One Markdown file for who you are and where you are, people and agents alike", { status: "0.2" }),
s("openskill", "OpenSkill", "Portable descriptions of human skills, knowledge and occupations, linked from OpenProfile", { status: "draft" }),
s("openagent", "OpenAgent", "A portable agent profile: identity, owner, skills and requested permissions", { status: "0.1" }),
s("openpersona", "OpenPersona.md", "One Markdown file for an agent's public persona, spoken voice and conversational style", { status: "0.1" }),
s("openwall", "OpenWall", "Consent-based broadcasts and direct messages across contact networks, with an AT Protocol mapping", { landing: undefined, status: "draft" }),
s("openresume", "OpenResume.md", "What you have done, in the same spirit, linked from the profile", { landing: undefined }),
s("openjob", "OpenJob", "What the work is, so a candidate's agent and a job board agree", { landing: undefined }),
Expand Down
2 changes: 2 additions & 0 deletions docs/openagent.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ An agent orchestration swarm is a set of sessions in OpenFleet. [OpenSwarm](/ope

[OpenProfile.md](/openprofile) is the human-readable identity, accounts and topics for a person or an agent. OpenAgent supplies the machine-readable capability and permission contract. A host can link both from the same profile page; neither format replaces the other or proves the other's ownership claims by itself.

[OpenPersona.md](/openpersona) is the optional public companion for an agent's role, spoken voice and conversational style. Keep the OpenAgent JSON unchanged: the host links the persona from the agent's profile page with `rel="openpersona"`, and the persona points back to the exact OpenAgent descriptor it describes. Persona prose is descriptive; it does not grant skills, permissions or authority, and a reader never executes it as a system prompt.

[OpenRental](/docs/openrental) already names agent members with `kind: "openagent"`. The member's `id` is the profile's `did`, and its HTTPS `url` points at this JSON document. A listing must check that the returned identity matches. Membership does not authorize execution or create a rental offer.

The profile's optional `pricing` is an indication, not a checkout contract. Explicit rental offers, their exact decimal-string rates and CoinPay settlement metadata belong in OpenRental. A consumer must not turn the profile's JSON number into a binding payment or charge an account merely because it fetched the file.
Expand Down
87 changes: 87 additions & 0 deletions docs/openpersona.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# OpenPersona.md

OpenPersona.md is one Markdown file for an agent's public persona: the role it presents to people, its spoken voice and the conversational style it aims to follow. It complements OpenAgent's identity and capability record. The agent's profile links the two; neither file is a prompt that a reader runs.

Status: **0.1**. A lightweight public companion to OpenAgent. Markdown is canonical; the file has no JSON schema and carries no permissions.

Slug: `openpersona`

## The shape

An OpenPersona.md names the OpenAgent descriptor it describes. The heading names the agent; the `OpenAgent` field is an absolute HTTPS URL to one `logicsrc.agent` JSON profile.

```md
# Research agent

- **OpenAgent**: https://example.com/agents/research.json
- **DID**: research.coinpay
- **Disclosure**: AI agent operated by Example Research

I find primary sources and prepare cited research briefs. I am concise, careful
about uncertainty and clear about which facts I verified.

## Voice

- **Description**: Clear, steady English with a measured pace.
- **Provider**: Example TTS service
- **Voice ID**: example-voice-id

## Conversation

- **Style**: Direct, calm and specific.
- **Turn-taking**: Answer direct questions; wait while another person is speaking.

## Boundaries

- **Limits**: Do not present an unverified claim as fact.
```

`OpenAgent` is required and MUST identify the exact JSON descriptor. `DID`, `Disclosure`, `## Voice`, `## Conversation` and `## Boundaries` are optional. Publishers may add prose and sections that help a reader understand the agent's public presentation. A voice provider and voice ID are descriptive metadata; they are not credentials and do not authorize a reader to call that provider.

## What the file means

The persona says how the agent describes its role and how it is intended to come across to people. Voice text may describe an audible voice or name a provider-specific voice reference. Conversation text may describe tone, turn-taking and the kinds of responses people can expect. Boundaries may explain the agent's limits in user-facing terms.

The document does not define an executable prompt, system message, tool list, permission, grant, account, availability, safety policy or service-level promise. Fetching or parsing it MUST NOT start the agent, call a tool, or grant access. A product may use it to display or compare profiles; the product owns any separate runtime policy and authorization.

The document is public profile content. Do not put secrets, private system prompts, private account details, internal host paths or instructions that should not be shown to the agent's users in it. A publisher may serve no persona file when they do not want to publish one.

## Relationship to OpenAgent and OpenProfile

[OpenAgent](/openagent) is the machine-readable identity, owner, skills and requested-permissions record. OpenPersona.md adds no fields to the `logicsrc.agent` schema. An OpenAgent reader continues to validate the same JSON shape.

[OpenProfile.md](/openprofile) carries a person's or agent's human-readable identity, accounts and topics. Its optional `Voice` key is a short preference for how a machine should sound when speaking for that person. OpenPersona.md gives an agent a dedicated place to describe its role and conversational style in more detail. The agent's OpenProfile page is the natural place to link its persona; the persona points back to the OpenAgent descriptor so a reader can check that it describes the intended agent.

When both links exist, a reader checks that the persona's `OpenAgent` URL resolves to a valid descriptor and that any stated `DID` equals the descriptor's `did`. A mismatch is shown as a mismatch; it is never silently repaired. Neither link proves that the publisher controls the descriptor or the voice provider account.

## Publication and discovery

Serve the file over HTTPS as `text/markdown; charset=utf-8`. A site representing one agent can use `/.well-known/openpersona.md`. A site serving multiple agents can use `/agents/research/openpersona.md` or another stable per-agent path.

The agent's profile page advertises the file:

```html
<link rel="openpersona" type="text/markdown" href="https://example.com/agents/research/openpersona.md">
```

An HTTP response may carry the equivalent `Link: <https://example.com/agents/research/openpersona.md>; rel="openpersona"; type="text/markdown"` header. The page should also link the OpenAgent JSON descriptor with `rel="openagent"`. The two records can live on different HTTPS hosts; the consumer keeps each source URL and applies its own fetch policy.

Public persona files must not contain access tokens or private keys. Fetching a persona is a read operation and never authorizes execution, payment, contact or use of its voice ID. The OpenAgent descriptor remains the source for identity and requested permissions; OpenFleet remains the source for a particular running session and its human sysop.

## Conformance

A **publisher** serves Markdown over HTTPS, names one OpenAgent descriptor URL, keeps any stated DID consistent with that descriptor, and publishes only persona information intended for public readers.

A **reader** preserves the persona URL, resolves its OpenAgent link, compares any stated DID, and treats persona prose and voice references as descriptive claims. It does not execute persona text or infer permissions, availability, ownership or provider access from it.

An **integrator** can display the persona beside the matching OpenAgent profile. It keeps runtime prompts, tools, credentials and authorization in its own protected configuration.

## Version history

| Version | Date | Change |
| --- | --- | --- |
| 0.1 | 2026-10-31 | Defines the public Markdown companion for agent persona and voice, linked to an unchanged OpenAgent descriptor |

## License

The specification text is CC BY 4.0.
1 change: 1 addition & 0 deletions docs/openprofile.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ By hand, in any editor, in five minutes. Or:

- [OpenSkill](/docs/openskill): human skills, knowledge and occupations linked from the optional Skills section.
- [OpenResume.md](/docs/openresume): what you have done, in the same spirit. A profile links to a resume through `Resume`; a resume links to a profile through `Profile` in its contact block.
- [OpenPersona.md](/openpersona): an optional companion for an agent's role, spoken voice and conversational style; the profile page links to it.
- [OpenBroadcast](/docs/openbroadcast) and [OpenGuest](/docs/openguest): the `Broadcast` and `Guest` sections, for matching hosts with guests.
- [OpenJob](/docs/openjob): what the work is.
- [OpenCreds](/opencreds): where the tokens behind the accounts are kept. A profile never contains a credential.
Expand Down
Loading