From fc6ba1b9461084206b5b5afd5a44740a32ceb974 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sun, 13 Sep 2026 12:36:52 +0000 Subject: [PATCH] Publish OpenAgent profile specification and discovery --- .../contract/spec-discovery.contract.test.ts | 1 + .../public/examples/openagent.json | 13 ++ apps/logicsrc-web/src/app/openagent/page.tsx | 66 +++++++++ apps/logicsrc-web/src/app/openfleet/page.tsx | 1 + apps/logicsrc-web/src/lib/specs.ts | 1 + docs/openagent.md | 134 ++++++++++++++++++ docs/openfleet.md | 1 + docs/openrental.md | 2 +- 8 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 apps/logicsrc-web/public/examples/openagent.json create mode 100644 apps/logicsrc-web/src/app/openagent/page.tsx create mode 100644 docs/openagent.md diff --git a/apps/logicsrc-web/contract/spec-discovery.contract.test.ts b/apps/logicsrc-web/contract/spec-discovery.contract.test.ts index fc70a617..a771bd1e 100644 --- a/apps/logicsrc-web/contract/spec-discovery.contract.test.ts +++ b/apps/logicsrc-web/contract/spec-discovery.contract.test.ts @@ -9,6 +9,7 @@ import sitemap from "../src/app/sitemap"; vi.mock("../src/lib/supabase", () => ({ publicClient: () => { throw new Error("offline"); } })); describe.each([ + { slug: "openagent", name: "OpenAgent", family: "people" }, { slug: "openabtest", name: "OpenABTest", family: "process" }, { slug: "openfleet", name: "OpenFleet", family: "process" }, { slug: "openrental", name: "OpenRental", family: "catalogs" }, diff --git a/apps/logicsrc-web/public/examples/openagent.json b/apps/logicsrc-web/public/examples/openagent.json new file mode 100644 index 00000000..edda8172 --- /dev/null +++ b/apps/logicsrc-web/public/examples/openagent.json @@ -0,0 +1,13 @@ +{ + "type": "logicsrc.agent", + "version": "0.1", + "name": "Research agent", + "did": "research.coinpay", + "owner_did": "operator.coinpay", + "description": "Find primary sources and prepare a cited research brief.", + "skills": ["research", "source-verification"], + "supported_task_types": ["research-brief"], + "permissions_requested": ["web:read"], + "polling_mode": true, + "public": true +} diff --git a/apps/logicsrc-web/src/app/openagent/page.tsx b/apps/logicsrc-web/src/app/openagent/page.tsx new file mode 100644 index 00000000..404c85b7 --- /dev/null +++ b/apps/logicsrc-web/src/app/openagent/page.tsx @@ -0,0 +1,66 @@ +import Link from "next/link"; +import type { Metadata } from "next"; +import { SiteShell } from "@/components/site-shell"; +import profile from "../../../public/examples/openagent.json"; +import { mono, pre, table, td } from "../openontology/ui"; + +export const metadata: Metadata = { + title: "OpenAgent · LogicSRC", + description: "A portable agent profile: identity, owner, skills and requested permissions in one JSON file, with bindings to OpenProfile, OpenFleet and OpenRental.", + alternates: { canonical: "/openagent" } +}; + +const LINKS = [ + ["OpenProfile.md", "/openprofile", "The identity, accounts and topics people read. Link the JSON descriptor from the same 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."], + ["OpenCreds", "/opencreds", "The vault for credentials. The public profile contains no secrets."] +]; + +export default function OpenAgentPage() { + return ( + +
+
+

People and agents · specification 0.1

+

OpenAgent

+

One file says who an agent is, who owns it, what it can do and which permissions it requests.

+
+

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.

+

Read the specification{" "}Download the example

+
+ +
+
+

The profile

+

An illustrative research agent. Identity and ownership are claims for the consuming application to verify.

+
+
{JSON.stringify(profile, null, 2)}
+

Seven required fields: type, version, name, did, owner_did, skills and permissions_requested. Skills must be nonempty. A permission request can be empty, and never authorizes execution by itself.

+
+ +
+
+

Serve it, link it, validate it

+
+

Serve one JSON profile over HTTPS. A domain for one agent can use /.well-known/openagent.json; a host with several agents gives each its own URL. Link the descriptor from its profile page:

+
{''}
+

Try the existing validator on the downloadable example:

+
{"curl -fsS https://logicsrc.com/examples/openagent.json -o agent.json\nnpx --yes --package @logicsrc/validators logicsrc-validate agent agent.json"}
+

Validation checks the shape. Ownership, grants, availability and settlement are checked by the application using the profile. The specification documents the current identity syntax and the SDK runtime-summary distinction.

+
+ +
+

How the pieces fit

+ + {LINKS.map(([name, href, description]) => ( + + ))} +
{name}{description}
+

OpenSwarm describes peer-to-peer file distribution. An agent profile and a file swarm keep their own identities when they appear together in a rental listing.

+
+
+ ); +} diff --git a/apps/logicsrc-web/src/app/openfleet/page.tsx b/apps/logicsrc-web/src/app/openfleet/page.tsx index e2954734..e46164c6 100644 --- a/apps/logicsrc-web/src/app/openfleet/page.tsx +++ b/apps/logicsrc-web/src/app/openfleet/page.tsx @@ -251,6 +251,7 @@ export default function OpenFleetPage(): ReactNode {

Where everything lives