diff --git a/apps/logicsrc-web/contract/spec-discovery.contract.test.ts b/apps/logicsrc-web/contract/spec-discovery.contract.test.ts
index 887229b5..57197edc 100644
--- a/apps/logicsrc-web/contract/spec-discovery.contract.test.ts
+++ b/apps/logicsrc-web/contract/spec-discovery.contract.test.ts
@@ -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" },
diff --git a/apps/logicsrc-web/public/examples/openpersona.md b/apps/logicsrc-web/public/examples/openpersona.md
new file mode 100644
index 00000000..f1df74f1
--- /dev/null
+++ b/apps/logicsrc-web/public/examples/openpersona.md
@@ -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.
diff --git a/apps/logicsrc-web/src/app/openagent/page.tsx b/apps/logicsrc-web/src/app/openagent/page.tsx
index e26d6336..85c7dbed 100644
--- a/apps/logicsrc-web/src/app/openagent/page.tsx
+++ b/apps/logicsrc-web/src/app/openagent/page.tsx
@@ -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."],
@@ -29,6 +30,7 @@ export default function OpenAgentPage() {
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.
The format is the existing logicsrc.agent contract. Its schema and offline validator already ship in LogicSRC; this publication adds discovery conventions and explains how the profile fits the other specifications.
+
Describe an agent's public persona in a separate OpenPersona.md file. The OpenAgent schema stays unchanged; link the companion from the same profile page and bind it back to this JSON descriptor.
diff --git a/apps/logicsrc-web/src/app/openpersona/page.tsx b/apps/logicsrc-web/src/app/openpersona/page.tsx
new file mode 100644
index 00000000..4bebd539
--- /dev/null
+++ b/apps/logicsrc-web/src/app/openpersona/page.tsx
@@ -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 (
+
+
+
+
People and agents ยท specification 0.1
+
OpenPersona.md
+
One Markdown file for an agent's public role, spoken voice and conversational style.
+
+
OpenPersona.md accompanies OpenAgent. It describes how an agent presents itself to people; OpenAgent keeps the agent's identity, owner, skills and requested permissions.
+
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.
The OpenAgent field binds this persona to one JSON descriptor. Voice provider details are optional descriptive metadata.
+
+
{EXAMPLE}
+
+
+
+
Publish and link
+
Serve one agent's file at /.well-known/openpersona.md, or serve it beside the agent page on a multi-agent host. The profile page links it with:
+
{''}
+
Keep OpenAgent's existing JSON schema unchanged. Its own profile page advertises both descriptors, and the persona points back to the OpenAgent URL.
+
+
+
+
How the pieces fit
+
+ {PIECES.map(([name, href, description]) => (
+
{name}
{description}
+ ))}
+
+
+
+ );
+}
diff --git a/apps/logicsrc-web/src/app/openprofile/page.tsx b/apps/logicsrc-web/src/app/openprofile/page.tsx
index 6cb322b9..a8de4331 100644
--- a/apps/logicsrc-web/src/app/openprofile/page.tsx
+++ b/apps/logicsrc-web/src/app/openprofile/page.tsx
@@ -274,6 +274,10 @@ export default function OpenProfilePage(): ReactNode {
OpenResume.md, what you have done, in the same
spirit; a profile links to a resume and a resume to a profile
+
+ OpenPersona.md, an optional companion for an agent's
+ role, spoken voice and conversational style
+
OpenJob, what the work is
diff --git a/apps/logicsrc-web/src/lib/specs.ts b/apps/logicsrc-web/src/lib/specs.ts
index 6f402329..1af37dcb 100644
--- a/apps/logicsrc-web/src/lib/specs.ts
+++ b/apps/logicsrc-web/src/lib/specs.ts
@@ -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 }),
diff --git a/docs/openagent.md b/docs/openagent.md
index c47d7710..619635b8 100644
--- a/docs/openagent.md
+++ b/docs/openagent.md
@@ -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.
diff --git a/docs/openpersona.md b/docs/openpersona.md
new file mode 100644
index 00000000..08afb14c
--- /dev/null
+++ b/docs/openpersona.md
@@ -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
+
+```
+
+An HTTP response may carry the equivalent `Link: ; 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.
diff --git a/docs/openprofile.md b/docs/openprofile.md
index 2b3821e8..9cb48dc8 100644
--- a/docs/openprofile.md
+++ b/docs/openprofile.md
@@ -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.