mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-02 12:54:03 +00:00
Add OpenProfile.md: one Markdown file for who and where, people and agents alike (#152)
A new LogicSRC spec at /openprofile with the document at /docs/openprofile. Eight degrading rules (name, identity block, headline, sections, accounts, topics, reshare terms, operator), three discovery locations (/.well-known/openprofile.md, rel="openprofile", a platform path) and verification by linking back. Registered in DOC_SLUGS, NAV, STATIC_ROUTES and llms.txt, the same four places as ASDLC. myna writes one from its accounts and publishes the Reshare section to the myna reshare network; agenticjobs serves one per public candidate. Claude-Session: https://claude.ai/code/session_01FMT2v1YxmgcDuionrfT719 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
00622f5882
commit
1a2d143a23
6 changed files with 445 additions and 0 deletions
|
|
@ -18,6 +18,7 @@ export function GET(): Response {
|
|||
## Standards & products
|
||||
|
||||
- [ASDLC](${SITE_URL}/asdlc): The Agentic Software Development Lifecycle: nine phases for building software when agents work in parallel and CI/CD is the only gate, with conformance levels and the ratchet rule.
|
||||
- [OpenProfile.md](${SITE_URL}/openprofile): One Markdown file that says who you are and where you are, for people and agents alike: identity block, accounts, topics, reshare terms and operator, discovered at /.well-known/openprofile.md or through rel="openprofile".
|
||||
- [AgentSwarm](${SITE_URL}/agent-swarm): Provider-neutral agent orchestration, model routing, and cost controls.
|
||||
- [AgentByte](${SITE_URL}/agentbyte): Agent screening sessions, policy events, and APIs.
|
||||
- [Credential Sharing](${SITE_URL}/credential-sharing): End-to-end-encrypted team vaults, plus source/target credential diffs, approval, sync, rollback, and audit.
|
||||
|
|
|
|||
258
apps/logicsrc-web/src/app/openprofile/page.tsx
Normal file
258
apps/logicsrc-web/src/app/openprofile/page.tsx
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
import Link from "next/link";
|
||||
import type { ReactNode } from "react";
|
||||
import type { Metadata } from "next";
|
||||
import { SiteShell } from "@/components/site-shell";
|
||||
import { mono, pre, table, td, th } from "../openontology/ui";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "OpenProfile.md · LogicSRC",
|
||||
description:
|
||||
"OpenProfile.md is one Markdown file that says who you are and where you are, for people and agents alike: an identity block, your accounts, your topics, the terms on which you reshare, and the operator behind an agent. Served at /.well-known/openprofile.md, linked with rel=\"openprofile\", verified by linking back.",
|
||||
alternates: { canonical: "/openprofile" }
|
||||
};
|
||||
|
||||
const EXAMPLE = `# Ada Lovelace
|
||||
|
||||
- **Kind**: person
|
||||
- **Handle**: @ada
|
||||
- **Web**: https://ada.example
|
||||
- **Pay**: eip155:8453:0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf
|
||||
- **Resume**: https://agenticjobs.work/candidates/ada/resume.md
|
||||
|
||||
Writes about machines that do not exist yet.
|
||||
|
||||
## Accounts
|
||||
|
||||
- [Bluesky](https://bsky.app/profile/ada.example)
|
||||
- [Mastodon](https://mathstodon.xyz/@ada)
|
||||
- [GitHub](https://github.com/ada)
|
||||
|
||||
## Topics
|
||||
|
||||
- computing, mathematics, poetry, #babbage
|
||||
|
||||
## Reshare
|
||||
|
||||
- **Networks**: bluesky, mastodon
|
||||
- **Rate**: $0.05/reshare
|
||||
- **Limit**: 3/day
|
||||
- **Not**: gambling, politics`;
|
||||
|
||||
const AGENT = `# Athena
|
||||
|
||||
- **Kind**: agent
|
||||
- **Handle**: @athena
|
||||
|
||||
Ships small fixes to open source projects, nightly.
|
||||
|
||||
## Operator
|
||||
|
||||
- **Name**: Ada Lovelace
|
||||
- **Profile**: https://ada.example/.well-known/openprofile.md`;
|
||||
|
||||
const RULES: Array<[string, string]> = [
|
||||
["One # heading", "It is the name. More than one and the first wins; none and the reader says it has no name."],
|
||||
["The identity block", "The bullet list under the name. Kind, Handle, Web, Email, Avatar, Pay, Resume are understood; unknown keys are kept as written."],
|
||||
["The headline", "One prose line between the block and the first ##. It is the bio a directory shows next to the name."],
|
||||
["## opens a section", "Kept verbatim and normalised for matching: accounts, topics, reshare, operator, links, about, projects, services, contact. Unknown sections are kept."],
|
||||
["Accounts", "One bullet per account and the URL is the identity. The network is derived from the host. An account is a claim until the page links back."],
|
||||
["Topics", "The words you would use to find yourself. Readers lowercase, strip #, and match loosely. No taxonomy at write time."],
|
||||
["Reshare", "What you will amplify for others and what it costs: Networks, Topics, Not, Rate, Limit. No section means no offer."],
|
||||
["Operator", "For an agent: the person answerable for it, by Name and Profile or Email. Chains are followed a few hops and reported."]
|
||||
];
|
||||
|
||||
const DISCOVERY: Array<[string, string, string]> = [
|
||||
["Well-known", "/.well-known/openprofile.md", "A domain that is a person or an agent. The canonical location for a personal site."],
|
||||
["Link relation", "<link rel=\"openprofile\" href=\"...\">", "Any HTML page, or a Link header on anything else. A platform points each profile page at its owner's file."],
|
||||
["Platform path", "/candidates/ada/openprofile.md", "A platform serving many people serves the file next to each profile page and links it from the page."]
|
||||
];
|
||||
|
||||
const ABSENT: Array<[string, string]> = [
|
||||
["No required fields", "A name and one line of prose is a valid file."],
|
||||
["No schema version", "Readers ignore what they do not recognise, so a file written today reads in five years."],
|
||||
["No signatures", "Verification is bidirectional linking, which every platform already supports in some form."],
|
||||
["No JSON", "A reader may derive a structured view and must regenerate it from the Markdown on every read. The Markdown is the canonical copy."]
|
||||
];
|
||||
|
||||
export default function OpenProfilePage(): ReactNode {
|
||||
return (
|
||||
<SiteShell active="OpenProfile">
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<p className="eyebrow">LogicSRC standards surface</p>
|
||||
<h2>OpenProfile.md</h2>
|
||||
<p>
|
||||
One Markdown file that says who you are and where you are, for people and agents alike.
|
||||
Meta tags for a profile: served by any site, linked from any platform, readable by
|
||||
anything.
|
||||
</p>
|
||||
</div>
|
||||
<p style={{ color: "#41505d" }}>
|
||||
Every platform has a profile page, and every profile page is a dead end. Your Bluesky bio
|
||||
cannot tell a job board what you write about. Your GitHub page cannot tell a resharing
|
||||
network which topics you will boost and what that costs. An agent has it worse: a handle on
|
||||
six networks, an operator somewhere behind it, and nowhere all of that is written down
|
||||
together. OpenProfile.md is that place. It ties a name to its accounts, its topics, its
|
||||
terms and, for an agent, the person answerable for it, in a form that survives being
|
||||
copied between tools.
|
||||
</p>
|
||||
<p style={{ color: "#5b6b7a" }}>
|
||||
Status: 0.1. A convention already in use by{" "}
|
||||
<a href="https://mynaposter.com">myna</a> and{" "}
|
||||
<a href="https://agenticjobs.work">agenticjobs</a>, published so others can serve and read
|
||||
the same file.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>The shape</h2>
|
||||
<p>A person, and the one section an agent adds.</p>
|
||||
</div>
|
||||
<pre style={pre}>{EXAMPLE}</pre>
|
||||
<pre style={pre}>{AGENT}</pre>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>The eight rules</h2>
|
||||
<p>Every one of them degrades rather than fails.</p>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={th}>Rule</th>
|
||||
<th style={th}>What it means</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{RULES.map(([rule, meaning], index) => (
|
||||
<tr key={rule}>
|
||||
<td style={td}>
|
||||
<strong>
|
||||
{index + 1}. {rule}
|
||||
</strong>
|
||||
</td>
|
||||
<td style={td}>{meaning}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Discovery</h2>
|
||||
<p>The file is served, not registered. A reader tries all three.</p>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={th}>Where</th>
|
||||
<th style={th}>How</th>
|
||||
<th style={th}>When</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{DISCOVERY.map(([where, how, when]) => (
|
||||
<tr key={where}>
|
||||
<td style={td}>
|
||||
<strong>{where}</strong>
|
||||
</td>
|
||||
<td style={td}>
|
||||
<code style={mono}>{how}</code>
|
||||
</td>
|
||||
<td style={td}>{when}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<p style={{ color: "#41505d", marginTop: "1rem" }}>
|
||||
Serve it as <code style={mono}>text/markdown; charset=utf-8</code>. A reader fetching the
|
||||
well-known location is reading, not saving, so no attachment disposition there.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Verification</h2>
|
||||
<p>An account is a claim until the page links back.</p>
|
||||
</div>
|
||||
<p style={{ color: "#41505d" }}>
|
||||
A listed account is verified when its platform page carries{" "}
|
||||
<code style={mono}>rel="openprofile"</code> or{" "}
|
||||
<code style={mono}>rel="me"</code> back to the file, or when the bio, website
|
||||
field or pinned post contains the file's URL in plain text. A reader shows verified and
|
||||
claimed accounts differently and hides neither, because most accounts are unverified for a
|
||||
while and a claim is still information. An agent that names its operator, and an operator
|
||||
whose file lists the agent under Accounts, are one trust chain: either link alone is a
|
||||
claim, both together are a verification.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>What is deliberately absent</h2>
|
||||
</div>
|
||||
<table style={table}>
|
||||
<tbody>
|
||||
{ABSENT.map(([what, why]) => (
|
||||
<tr key={what}>
|
||||
<td style={td}>
|
||||
<strong>{what}</strong>
|
||||
</td>
|
||||
<td style={td}>{why}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Writing and reading one</h2>
|
||||
</div>
|
||||
<ul style={{ color: "#41505d", lineHeight: 1.9, paddingLeft: "1.1rem" }}>
|
||||
<li>
|
||||
By hand, in any editor, in five minutes. Then serve it at{" "}
|
||||
<code style={mono}>/.well-known/openprofile.md</code>.
|
||||
</li>
|
||||
<li>
|
||||
<code style={mono}>myna profile write</code> builds one from the accounts myna is logged
|
||||
into and the topics in its settings. <code style={mono}>myna reshare join</code>{" "}
|
||||
publishes the Reshare section to the myna reshare network, which matches authors and
|
||||
sharers by topic and settles the rate through CoinPay when there is one.
|
||||
</li>
|
||||
<li>
|
||||
agenticjobs serves one for every public candidate at{" "}
|
||||
<code style={mono}>/candidates/<slug>/openprofile.md</code>, derived from the
|
||||
candidate's OpenResume.md, and links it from the profile page.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="band">
|
||||
<div className="section-head">
|
||||
<h2>Where everything lives</h2>
|
||||
</div>
|
||||
<ul style={{ color: "#41505d", lineHeight: 1.9, paddingLeft: "1.1rem" }}>
|
||||
<li>
|
||||
<Link href="/docs/openprofile">Specification</Link>, with the eight rules, discovery,
|
||||
verification and the version history
|
||||
</li>
|
||||
<li>
|
||||
<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="/docs/openjob">OpenJob</Link>, what the work is
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/opencreds">OpenCreds</Link>, where the tokens behind the accounts are kept;
|
||||
a profile never contains a credential
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</SiteShell>
|
||||
);
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ const STATIC_ROUTES: Array<{
|
|||
{ path: "/openswarm", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openprd", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/asdlc", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openprofile", changeFrequency: "weekly", priority: 0.9 },
|
||||
{ path: "/openontology/explore", changeFrequency: "daily", priority: 0.7 },
|
||||
{ path: "/openspec", changeFrequency: "weekly", priority: 0.8 },
|
||||
{ path: "/agent-swarm", changeFrequency: "weekly", priority: 0.8 },
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const NAV: Array<{ href: string; label: string; external?: boolean }> = [
|
|||
{ href: "/openswarm", label: "OpenSwarm" },
|
||||
{ href: "/openprd", label: "OpenPRD" },
|
||||
{ href: "/asdlc", label: "ASDLC" },
|
||||
{ href: "/openprofile", label: "OpenProfile" },
|
||||
{ href: "/#cli", label: "CLI" },
|
||||
{ href: "/docs", label: "Docs" },
|
||||
{ href: "/blog", label: "Blog" },
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export const DOC_SLUGS = [
|
|||
"openontology-interoperability",
|
||||
"openjob",
|
||||
"openresume",
|
||||
"openprofile",
|
||||
"openstream",
|
||||
"openspec-comparison",
|
||||
"data-model",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue