Skip to content
Open
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **`memory` listing type**: `positronick memory search|list|show|install` — platform LISTING_TYPES
- **Listing categories**: Memory and Observability on admin validation
- **`positronick research`**: the agent-facing "what's new" feed over positronick.com's published blog posts, mirrored GitHub releases, and mirrored news links — newest first, so agents avoid stale knowledge. Filter with `--kind` (article/release/link), `--category`, `--tag`, or a free-text query, and poll just the delta with `--since <iso>`; the printed `latest` timestamp is the value to pass back next time. Read-only and unauthenticated, like the soul/listing reads. Backed by the public `GET /api/research` endpoint.
- **`positronick blog`**: read the positronick.com blog from the terminal — `blog list` (newest first, optional `--kind` article/release/link) and `blog show <slug>`, with `--raw` printing the markdown body verbatim and did-you-mean hints (exit 3) on a missing slug. Read-only and unauthenticated, mirroring the soul/listing reads. Backed by the public `GET /api/blog`, `/api/blog/{slug}`, and `/api/blog/{slug}.md` endpoints.
- **`positronick feed` (admin)**: manage the blog feed sources (GitHub release / RSS mirroring) the ingestor polls — `feed list`, `feed create --label <l> --feed-url <u> --kind github_release|rss --category <c>` (`--author`/`--listing` attribution, repeatable `--tag`, `--auto-publish`, `--enabled`), `feed update <id>` (`--enabled=false` pauses a feed — there is no delete verb), and `feed sync <id>` (ingest one feed now, surfacing the fetch summary; a fetch/parse failure maps the API's 502 to a clear error). Backed by the `/api/admin/feeds` API. Ingesting every feed on a schedule stays the cron's job — no CLI subcommand carries that admin key.
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Positronick CLI

`positronick` discovers and installs agent capabilities — souls, harnesses, CLIs, MCP servers, agents, skills, plugins, and loops — from [positronick.com](https://positronick.com).
`positronick` discovers and installs agent capabilities — souls, harnesses, CLIs, MCP servers, memory, agents, skills, plugins, and loops — from [positronick.com](https://positronick.com).

## Install

Expand Down Expand Up @@ -38,6 +38,7 @@ yay -S positronick-bin # Arch (AUR)
| `positronick harness search\|show\|list\|install` | Agent harnesses | available |
| `positronick cli search\|show\|list\|install` | CLI tools | available |
| `positronick mcp search\|show\|list\|install` | MCP servers | available |
| `positronick memory search\|show\|list\|install` | Memory and context engines | available |
| `positronick agent search\|show\|list\|install` | Agents | available |
| `positronick skill search\|show\|list\|install` | Skills | available |
| `positronick plugin search\|show\|list\|install` | Plugins | available |
Expand Down
9 changes: 8 additions & 1 deletion internal/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ import (

// ListingTypes are the kinds of official tooling the registry catalogs.
// Mirrors LISTING_TYPES in src/lib/types.ts.
var ListingTypes = []string{"harness", "cli", "mcp", "agent", "skill", "plugin", "loop"}
var ListingTypes = []string{"harness", "cli", "mcp", "memory", "agent", "skill", "plugin", "loop"}

// ListingCategories are the broad subject labels a listing may use.
// Mirrors LISTING_CATEGORIES in src/lib/types.ts.
var ListingCategories = []string{
"AI/ML", "Memory", "Observability", "DevOps", "Cloud", "Web",
"Data", "Security", "Technical", "Productivity",
}

// FeedKinds are the kinds of blog feed source the ingestor mirrors. Mirrors
// FEED_KINDS in src/lib/server/feedFields.ts.
Expand Down
22 changes: 22 additions & 0 deletions internal/api/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,25 @@ func TestNewWireFieldsRoundTrip(t *testing.T) {
t.Errorf("SoulCard.ChargeCount = %d, want 5", s.ChargeCount)
}
}

// Platform LISTING_TYPES order is a public contract: the CLI auto-registers one
// cobra noun per entry, skill_contract pins the joined list, and MCP type enums
// derive from it. Keep this in lockstep with src/lib/types.ts.
func TestListingTypesMatchPlatformOrder(t *testing.T) {
want := []string{"harness", "cli", "mcp", "memory", "agent", "skill", "plugin", "loop"}
if !reflect.DeepEqual(ListingTypes, want) {
t.Fatalf("ListingTypes = %#v\nwant %#v", ListingTypes, want)
}
}

// Platform LISTING_CATEGORIES order is a public contract: mockadmin validation
// and any future UI filters must accept exactly these labels.
func TestListingCategoriesMatchPlatformOrder(t *testing.T) {
want := []string{
"AI/ML", "Memory", "Observability", "DevOps", "Cloud", "Web",
"Data", "Security", "Technical", "Productivity",
}
if !reflect.DeepEqual(ListingCategories, want) {
t.Fatalf("ListingCategories = %#v\nwant %#v", ListingCategories, want)
}
}
4 changes: 2 additions & 2 deletions internal/cli/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,8 @@ func newListingCmd() *cobra.Command {
cmd := markAdmin(&cobra.Command{
Use: "listing",
Short: "Create and update registry listings (admin)",
Long: "Write access to registry listings of any type — the public type nouns (harness, " +
"cli, mcp, agent, skill, plugin, loop) stay read-only. Listings are authored by an " +
Long: "Write access to registry listings of any type — the public type nouns (" +
strings.Join(api.ListingTypes, ", ") + ") stay read-only. Listings are authored by an " +
"existing profile handle; profiles themselves stay git-curated." + adminNote,
})
cmd.AddCommand(newListingCreateCmd(), newListingUpdateCmd())
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/agentdocs.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var exitCodeMeanings = map[string]string{

const agentDocsIntro = "`positronick` is the command-line client for positronick.com. It discovers agent " +
"capabilities: souls (installable SOUL.md personality files), a registry of official " +
"tooling (harnesses, CLIs, MCP servers, agents, skills, plugins, loops), and a `research` " +
"tooling (harnesses, CLIs, MCP servers, memory, agents, skills, plugins, loops), and a `research` " +
"feed of what's new (articles, releases, links) so agents avoid stale knowledge. It is built to be " +
"driven by coding agents — pass `--json` to any command for stable machine-readable JSON on " +
"stdout, read progress and errors from stderr, and branch on the exit code. Read commands " +
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func attachInstallCommands(root *cobra.Command) {
c.AddCommand(newSoulInstallCmd())
case "loop":
c.AddCommand(newLoopInstallCmd())
case "harness", "cli", "mcp", "agent", "skill", "plugin":
case "harness", "cli", "mcp", "memory", "agent", "skill", "plugin":
c.AddCommand(newListingInstallCmd(c.Name()))
}
}
Expand Down
14 changes: 10 additions & 4 deletions internal/cli/listing.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,29 @@ type listingDetail struct {
}

// listingNounShorts gives each registry noun its own help line.
// Keys mirror api.ListingTypes (harness, cli, mcp, memory, agent, skill, plugin, loop).
var listingNounShorts = map[string]string{
"harness": "Discover agent harnesses in the registry",
"cli": "Discover official CLI tools in the registry",
"mcp": "Discover MCP servers in the registry",
"memory": "Discover memory and context engines in the registry",
"agent": "Discover agent SDKs and frameworks in the registry",
"skill": "Discover agent skills in the registry",
"plugin": "Discover agent plugins in the registry",
"loop": "Discover reusable agent loops in the registry",
}

// newListingNounCmd builds one registry noun (harness, cli, mcp, agent,
// skill, plugin, loop) with the shared search/list/show verbs, each scoped to
// its listing type via ?type= on the API.
// newListingNounCmd builds one registry noun from api.ListingTypes with the
// shared search/list/show verbs, each scoped to its listing type via ?type=
// on the API.
func newListingNounCmd(listingType string) *cobra.Command {
short := listingNounShorts[listingType]
if short == "" {
short = fmt.Sprintf("Discover %s listings in the registry", listingType)
}
cmd := &cobra.Command{
Use: listingType,
Short: listingNounShorts[listingType],
Short: short,
}
cmd.AddCommand(
newListingSearchCmd(listingType),
Expand Down
75 changes: 75 additions & 0 deletions internal/cli/testdata/golden/agent-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,81 @@
"description": "Show one mcp listing in full",
"flags": []
},
{
"path": "positronick memory",
"use": "positronick memory [flags]",
"description": "Discover memory and context engines in the registry",
"flags": []
},
{
"path": "positronick memory install",
"use": "positronick memory install \u003cslug\u003e [flags]",
"description": "Print (or run with --run) the official install command for one memory",
"flags": [
{
"name": "run",
"shorthand": "",
"usage": "execute the install command via `sh -c` instead of printing it",
"default": "false"
}
]
},
{
"path": "positronick memory list",
"use": "positronick memory list [flags]",
"description": "List all memory listings",
"flags": [
{
"name": "category",
"shorthand": "",
"usage": "only results in this category (case-insensitive)",
"default": ""
},
{
"name": "limit",
"shorthand": "",
"usage": "maximum number of results",
"default": "20"
},
{
"name": "sort",
"shorthand": "",
"usage": "sort order: relevance, name, downloads or newest",
"default": "name"
}
]
},
{
"path": "positronick memory search",
"use": "positronick memory search \u003cquery\u003e [flags]",
"description": "Search memory listings by fuzzy relevance",
"flags": [
{
"name": "category",
"shorthand": "",
"usage": "only results in this category (case-insensitive)",
"default": ""
},
{
"name": "limit",
"shorthand": "",
"usage": "maximum number of results",
"default": "20"
},
{
"name": "sort",
"shorthand": "",
"usage": "sort order: relevance, name, downloads or newest",
"default": "relevance"
}
]
},
{
"path": "positronick memory show",
"use": "positronick memory show \u003cslug\u003e [flags]",
"description": "Show one memory listing in full",
"flags": []
},
{
"path": "positronick plugin",
"use": "positronick plugin [flags]",
Expand Down
48 changes: 47 additions & 1 deletion internal/cli/testdata/golden/agent-docs.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# positronick — agent manual

`positronick` is the command-line client for positronick.com. It discovers agent capabilities: souls (installable SOUL.md personality files), a registry of official tooling (harnesses, CLIs, MCP servers, agents, skills, plugins, loops), and a `research` feed of what's new (articles, releases, links) so agents avoid stale knowledge. It is built to be driven by coding agents — pass `--json` to any command for stable machine-readable JSON on stdout, read progress and errors from stderr, and branch on the exit code. Read commands never prompt. Hidden admin commands (create/update for souls and listings, create/list for profiles, list/create/update/sync for blog feed sources, and create/update/list for blog posts) exist and appear in help and in these docs after logging in with an admin account.
`positronick` is the command-line client for positronick.com. It discovers agent capabilities: souls (installable SOUL.md personality files), a registry of official tooling (harnesses, CLIs, MCP servers, memory, agents, skills, plugins, loops), and a `research` feed of what's new (articles, releases, links) so agents avoid stale knowledge. It is built to be driven by coding agents — pass `--json` to any command for stable machine-readable JSON on stdout, read progress and errors from stderr, and branch on the exit code. Read commands never prompt. Hidden admin commands (create/update for souls and listings, create/list for profiles, list/create/update/sync for blog feed sources, and create/update/list for blog posts) exist and appear in help and in these docs after logging in with an admin account.

Exit codes:

Expand Down Expand Up @@ -404,6 +404,52 @@ Usage: `positronick mcp show <slug> [flags]`

Show one mcp listing in full

## positronick memory

Usage: `positronick memory [flags]`

Discover memory and context engines in the registry

## positronick memory install

Usage: `positronick memory install <slug> [flags]`

Print (or run with --run) the official install command for one memory

Flags:

- `--run` (default `false`): execute the install command via `sh -c` instead of printing it

## positronick memory list

Usage: `positronick memory list [flags]`

List all memory listings

Flags:

- `--category` (default ``): only results in this category (case-insensitive)
- `--limit` (default `20`): maximum number of results
- `--sort` (default `name`): sort order: relevance, name, downloads or newest

## positronick memory search

Usage: `positronick memory search <query> [flags]`

Search memory listings by fuzzy relevance

Flags:

- `--category` (default ``): only results in this category (case-insensitive)
- `--limit` (default `20`): maximum number of results
- `--sort` (default `relevance`): sort order: relevance, name, downloads or newest

## positronick memory show

Usage: `positronick memory show <slug> [flags]`

Show one memory listing in full

## positronick plugin

Usage: `positronick plugin [flags]`
Expand Down
3 changes: 2 additions & 1 deletion internal/cli/testdata/golden/mcp-tools-list.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[
{
"description": "Search positronick.com's registry of verified agent tooling — harnesses, CLIs, MCP servers, agent SDKs, skills, plugins and loops — ranked by fuzzy relevance. Follow up with listing_show for the full record.",
"description": "Search positronick.com's registry of verified agent tooling — harnesses, CLIs, MCP servers, memory, agent SDKs, skills, plugins and loops — ranked by fuzzy relevance. Follow up with listing_show for the full record.",
"inputSchema": {
"additionalProperties": false,
"properties": {
Expand All @@ -24,6 +24,7 @@
"harness",
"cli",
"mcp",
"memory",
"agent",
"skill",
"plugin",
Expand Down
2 changes: 1 addition & 1 deletion internal/mcpserver/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const serverInstructions = `positronick is the registry of agent capabilities on

Souls are installable SOUL.md personality files: soul_search → soul_show →
soul_install. The wider registry of verified tooling (harnesses, CLIs, MCP
servers, agents, skills, plugins, loops): listing_search → listing_show.
servers, memory, agents, skills, plugins, loops): listing_search → listing_show.

Search results are slim cards; always fetch the full record with the _show
tool before acting on an entry. soul_install has side effects — it counts
Expand Down
2 changes: 1 addition & 1 deletion internal/mcpserver/listings.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func addListingTools(srv *mcp.Server, opts Options) {
mcp.AddTool(srv, &mcp.Tool{
Name: "listing_search",
Description: "Search positronick.com's registry of verified agent tooling — harnesses, " +
"CLIs, MCP servers, agent SDKs, skills, plugins and loops — ranked by fuzzy " +
"CLIs, MCP servers, memory, agent SDKs, skills, plugins and loops — ranked by fuzzy " +
"relevance. Follow up with listing_show for the full record.",
InputSchema: inputSchema[listingSearchIn](func(s *jsonschema.Schema) {
s.Properties["type"].Enum = enumOf(api.ListingTypes)
Expand Down
4 changes: 3 additions & 1 deletion internal/mockapi/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ const (
)

// Enum fixtures mirroring src/lib/types.ts in the product repo.
// Listing categories come from api.ListingCategories so mockadmin validation
// stays in lockstep with the platform LISTING_CATEGORIES contract.
var (
soulCategories = []string{"Technical", "Professional", "Creative", "Educational", "Wellness", "Research", "Experimental", "Playful"}
soulFrameworks = []string{"hermes", "openclaw", "claude-code", "cursor"}
listingCategories = []string{"AI/ML", "DevOps", "Cloud", "Web", "Data", "Security", "Technical", "Productivity"}
listingCategories = api.ListingCategories
statuses = []string{"draft", "pending", "published"}
)

Expand Down
6 changes: 3 additions & 3 deletions skills/positronick/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
name: positronick
description: >-
Discover and install agent capabilities from the positronick.com registry —
souls (SOUL.md personality files), harnesses, CLIs, MCP servers, agents,
skills, plugins, and loops. Use when asked to find or install a soul or
souls (SOUL.md personality files), harnesses, CLIs, MCP servers, memory,
agents, skills, plugins, and loops. Use when asked to find or install a soul or
SOUL.md, browse positronick listings, set up a loop recipe, or whenever the
positronick MCP tools or `positronick` CLI are available and the task
involves agent tooling discovery.
Expand Down Expand Up @@ -48,7 +48,7 @@ Souls are installable SOUL.md personality files for coding agents.
## Registry listings: search → show

Everything else is a listing with one of these types: `harness`, `cli`,
`mcp`, `agent`, `skill`, `plugin`, `loop`.
`mcp`, `memory`, `agent`, `skill`, `plugin`, `loop`.

1. `listing_search` — scope with `type`, filter with `category`. Cards carry
the official `installCmd` and verified `sourceUrl`.
Expand Down