Skip to content

feat(skills): Skills page and SkillMarketplace registration - #225

Merged
justinwilkin merged 194 commits into
mainfrom
feat/skills-marketplace
Nov 5, 2026
Merged

justinwilkin merged 194 commits into
mainfrom
feat/skills-marketplace

Conversation

@Stoyan12314

@Stoyan12314 Stoyan12314 commented Aug 31, 2026 •

Copy link
Copy Markdown
Member

What and why

Implements Agent Skills (PRD): a read-only Skills page where tenant members find and read agent skills from the GitHub repositories their tenant registers.

  • Registration: a tenant declares each Marketplace as a SkillMarketplace (runkora.io/v1alpha1) in its namespace, with the repository, an optional ref, a required origin (internal or external) and the GitHub App that reads it. The operator renders every tenant's Marketplaces into the kora-skill-marketplaces ConfigMap and their App keys into the kora-skill-marketplace-secrets Secret in kora-system, and reports Aggregated, Pending or Invalid with a reason such as CredentialUnavailable in status.
  • skills-service: a new binary on port 8098 serves /v1/marketplaces behind skills:read. Each Marketplace is read with an installation token scoped to its one repository and contents:read, and a public repository outside the installation falls back to a metadata:read token. The ref resolves to a commit, SKILL.md files are read on crawl and supporting files when opened, within limits set in the chart.
  • Cache: skill lists sit in Redis per tenant and Marketplace. After the cache TTL the service checks the commit and crawls again only when it moved, a skill could not be read, or the limits changed. A refused credential or a missing repository fails closed, and a cached list is served through a GitHub outage, timeout or rate limit for at most two TTLs. A Marketplace's cached supporting files are capped at fileCacheBytesPerMarketplace (32 MiB) in stored bytes, and files over the cap are served uncached.
  • Dashboard: /skills lists skills across Marketplaces in title order, ten per page, as cards or a table, with Marketplace and Favourites chips, search, and an origin badge on each card. Favourites are stored in the preferences document. The skill page renders SKILL.md with a raw view, a file explorer, the source repository, origin and commit, a View source link at that commit, and Share.
  • Chart: the skills-service Deployment, Service, metrics, the /v1/marketplaces route on the api host, and a ServiceEntry for api.github.com under the platform egress policy.

Cache layout, operator resync and the shared GitHub App code are tracked in #920.

How it was tested

  • make check passes, including a Redis cache test against a RESP fake and chart tests for the route, metrics and ServiceEntry.
  • On the local cluster against anthropics/skills, read through the metadata-only fallback:
    • Browse, search, favourites, the list view and origin badges.
    • The skill page, file loading, View source and Share.
    • A commit check after the TTL makes one GitHub call when the commit has not moved.
    • A SkillMarketplace without origin is rejected at admission.
    • /v1/marketplacesX does not reach skills-service.
  • On the local cluster against a private repository with the App installed, read with the installation's contents:read token: the list, a skill page with 313 files, and a nested file.
  • Only checked in Chromium.

Checklist

@Stoyan12314
Stoyan12314 requested a review from a team as a code owner August 31, 2026 06:49
@SarthakJoshi18
SarthakJoshi18 force-pushed the feat/skills-marketplace branch from 07841e6 to 3d6fc3a Compare October 6, 2026 10:09
Copilot AI balanced review requested due to automatic review settings October 6, 2026 10:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Core terminology, authorization, and file-preview acceptance criteria remain ambiguous or inconsistent.

Review effort: Balanced
Findings: 4 Medium severity · 2 Low severity

Open (6)
What changed in this PR

Adds the Agent Marketplace PRD to define tenant-scoped, read-only skill discovery before related ADRs and implementation.

Changes:

  • Defines V1 goals, scope, requirements, and acceptance criteria.
  • Adds the PRD to the repository index.
File Description
docs/​prd/​agent-marketplace.md Defines Marketplace product requirements.
docs/​prd/​README.md Indexes the new draft PRD.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/prd/agent-marketplace.md Resolved
Comment thread docs/prd/agent-marketplace.md Resolved
Comment thread docs/prd/agent-marketplace.md Resolved
Comment thread docs/prd/agent-marketplace.md Resolved
Comment thread docs/prd/agent-marketplace.md Resolved
Comment thread docs/prd/agent-marketplace.md Resolved
@siddhantp2003
siddhantp2003 requested a review from a team as a code owner November 4, 2026 05:10
@siddhantp2003
siddhantp2003 force-pushed the feat/skills-marketplace branch from 47dd642 to 3d6fc3a Compare November 4, 2026 05:54
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Diagrams changed in this PR

Diagram Rendered
marketplace view rendered

The Files changed tab shows a before-and-after image diff for each SVG.

@runkora

runkora Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Visual Walkthrough

This pull request adds a skill marketplace: an operator that renders SkillMarketplace resources, each tagged internal or external, into kora-system objects, and a skills-service that lists and reads skills from GitHub.

Browsing skills

A skills request reads the cached list, keeps it when the commit is unchanged, and crawls GitHub when the commit changed or the list is partial.

sequenceDiagram
    participant C as Client
    participant H as Skills handlers
    participant S as Skills service
    participant K as Redis cache
    participant R as Crawler
    participant G as GitHub
    C->>H: list skills
    alt invalid offset or limit
        H-->>C: 400 invalid request
    else valid page
        H->>S: list skills
        alt no usable key
            S-->>H: 502 credential unavailable
        else key usable
            S->>K: read cached list
            K-->>S: cached list
            alt cache fresh
                S-->>H: cached skills
            else cache stale or missing
                S->>R: revalidate or crawl
                R->>G: resolve commit
                alt resolve outage or rate limit
                    G-->>R: outage or rate limit
                    R-->>S: keep stale list when cached
                else commit unchanged and list reusable
                    G-->>R: same commit
                    R-->>S: keep cached list
                else commit changed, partial or other limits
                    R->>G: read tree and SKILL.md files
                    alt crawl outage or rate limit
                        G-->>R: outage or rate limit
                        R-->>S: keep stale list when cached
                    else other failure
                        G-->>R: not found
                        R-->>S: 404 or 502 fail closed
                    else read succeeded
                        G-->>R: tree and SKILL.md files
                        R-->>S: skill list
                        S->>K: store list
                        S-->>H: skills
                    end
                end
            end
        end
    end
    H-->>C: skill page
Loading
Node Code Symbols
Skills handlers handlers.go handleListSkills, apiError
Skills service service.go ListSkills, list, revalidate
Redis cache cache.go GetList, SetList, GetFailure
Crawler crawler.go Crawl, Reusable, ResolveCommit
Marketplace aggregation

The operator renders each SkillMarketplace, with its origin, into a ConfigMap and Secret that skills-service reads from mounted files.

flowchart TB
    subgraph op[kora-operator]
        Rec[SkillMarketplace reconciler]
        TR[Tenant reconciler]
        Agg[Marketplace aggregator]
    end
    subgraph sys[kora-system]
        CM[ConfigMap kora-skill-marketplaces]
        Sec[Secret kora-skill-marketplace-secrets]
        Reg[Skills registry]
    end
    SM[SkillMarketplace resource] --> Rec
    Rec --> Agg
    TR --> Agg
    Agg --> CM
    Agg --> Sec
    Agg --> St[SkillMarketplace status]
    CM -->|origin checked on load| Reg
    Sec --> Reg
    classDef added fill:#1f883d,stroke:#1a7f37,stroke-width:2px,color:#ffffff
    classDef changed fill:#bf8700,stroke:#9a6700,stroke-width:2px,color:#ffffff
    classDef removed fill:#cf222e,stroke:#a40e26,stroke-width:2px,stroke-dasharray:5,color:#ffffff
    classDef context fill:transparent,stroke:#8c959f,stroke-width:1px,stroke-dasharray:3,color:#8c959f
    linkStyle default stroke:#8c959f,stroke-width:2px
    class SM,Rec,Agg,CM,Sec,Reg,St added
    class TR changed
    style op fill:transparent,stroke:#8c959f
    style sys fill:transparent,stroke:#8c959f
Loading

Legend: green = added, amber = changed, red = removed, dashed grey = context

Node Code Symbols
SkillMarketplace resource skillmarketplace_types.go SkillMarketplaceSpec, Origin, repoKey
SkillMarketplace reconciler skillmarketplace_controller.go Reconcile, SetupWithManager
Tenant reconciler tenant_controller.go MarketplaceAggregator
Marketplace aggregator skillmarketplace_aggregator.go Sync, buildMarketplaces, collectKeys
ConfigMap kora-skill-marketplaces skillmarketplace_aggregator.go upsertConfigMap
Secret kora-skill-marketplace-secrets skillmarketplace_aggregator.go upsertSecret
Skills registry registry.go NewRegistry, reload, build
SkillMarketplace status skillmarketplace_aggregator.go updateStatuses, setStatus

@runkora runkora Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walkthrough

Adds the Agent Skills marketplace: a SkillMarketplace CRD and operator aggregator, a skills-service backend with GitHub crawling and Redis caching, Helm chart wiring, and a dashboard Skills UI.

Severity Finding Location
medium Bound the total size of aggregated keys backend/internal/operator/skillmarketplace_aggregator.go:191
medium Strip only a closing # sequence from titles backend/internal/skills/formatter.go:111
medium Check how nested file paths are encoded backend/internal/platform/clients/github/client.go:395
medium Expose skills-service metrics to the ServiceMonitor charts/kora/templates/skills-service/config.yaml:15
medium Store SKILL.md content apart from the list metadata backend/internal/skills/cache.go:56
medium Add tests for the Redis cache backend/internal/skills/cache.go:1
nit Reject non-positive cache TTLs backend/cmd/skills-service/config/config.go:84
nit Serve marketplaces under /api/v1 charts/kora/templates/api/virtualservice.yaml:170

Review effort: Very high. Split into operator, skills-service, chart and frontend PRs.
Risk: High, new service, CRD, secrets aggregation and public route
Coverage: 147 of 147 files reviewed

Where to focus

Area Why it needs a person
backend/internal/operator/skillmarketplace_aggregator.go Decide how tenant GitHub App keys are bounded in one shared Secret.
backend/internal/platform/clients/github/client.go Verify GitHub accepts encoded slashes in contents paths.
backend/internal/skills/cache.go Decide the cache layout for large SKILL.md content and add tests.
charts/kora/templates/skills-service/ Confirm metrics scraping and route prefix for the new service.

Lower risk

Area Why
frontend/src/app/(dashboard)/skills/ UI components and stories over a server-side data layer.
docs/ Documentation and index entries.
*_test.go Test files with no production logic.
Changes by area
Area Files Change
backend/internal/operator 13 SkillMarketplace CRD, controller and aggregator
backend/internal/skills, backend/cmd/skills-service 19 New skills service
backend/internal/platform 6 GitHub client methods, marketplace file format, chart tests
charts/, deploy/, scripts/ 25 Chart, CRD and local deploy wiring
docs/ 14 PRD, ADR, guides
frontend/ 70 Skills pages, API routes, e2e, preferences
Checked

Operator controllers and tests, skills handlers and token handling, frontend skills routes and server client.

Comment thread backend/internal/skills/formatter.go Resolved
Comment thread backend/internal/skills/cache.go Resolved
Comment thread backend/internal/skills/cache.go Resolved

@runkora runkora Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walkthrough

Adds an origin field (internal or external) to SkillMarketplace, the skills-service API and the Skills UI. Also fixes the earlier review points on titles, metrics, TTLs, routes and cache tests.

Severity Finding Location
nit Serialize registry reloads backend/internal/skills/registry.go:241

Review effort: High
Risk: Medium, new origin field in CRD and API
Coverage: 52 of 52 files reviewed

Where to focus

Area Why it needs a person
backend/internal/skills/registry.go Decide whether overlapping debounced reloads need serialization.
backend/internal/operator/skillmarketplace_types.go Confirm required origin needs no default for existing resources.
Checked

Skills crawler and service caching, chart templates, Skills UI and tests.

Comment thread backend/internal/skills/registry.go Resolved
@justinwilkin justinwilkin changed the title docs(prd): add Agent Marketplace requirements feat(skills): Skills page and SkillMarketplace registration Nov 5, 2026
Stoyan12314 and others added 13 commits November 5, 2026 15:20
Created the interfaces for the datatypes and created mock data, skills, that will be used for UI work
… Add Previous and Next pagination with URL state, Implement Marketplace overview request and availability states

Covers pieces of three Notion stories under Marketplace Frontend Backlog. None fully meet their acceptance criteria, nothing here should close a ticket yet.

Filters ticket done: no auto-select, "Select a Marketplace" prompt when none chosen, no Skill request until selected, alphabetical Marketplace order. Left: a Marketplace ID distinct from display name, the "Marketplace not available" error message, and the recorded responsive layout.

Pagination ticket done: marketplace/page/pageSize in the URL, Previous/Next boundary disabling, page sizes 12/24/48 default 24. Left: offset validation and reset notice, scroll/keyboard-focus on page change, push vs replace history distinction, pageSize clamping for unsupported values, disabling controls during a pending request.

Availability-states ticket: not implemented, beyond the no-selection prompt it shares with the filters ticket. No request-state model, no Current/Stale/Degraded/Pending/Unavailable/Not-configured handling, no Forbidden or session-expiry handling, no "Showing previous results," no manual Retry.
Updated the ADR for the Agent Marketplace Frontend Architecture to reflect changes in the development of it.
- Load the first result page on the server, and later browse changes
  through /api/marketplace/skills
- Add search, sort, rows per page, page buttons, and a list or card view
- Add loading and error notices that keep the current results on screen
- Save the last selected Marketplace in the user preferences
- Keep the browse values in the Skill URL for the header Back button
- Add a retry to the Skill page, and move the mock client and fixtures
  to src/server
- Make ViewToggle a component and move it to src/components (Tier 2)
- Update the frontend ADR

Exclude the tests until the skills-service API is ready, so that they
come in one complete change.

Complete these Notion stories (Marketplace Frontend Backlog):
- Build Marketplace overview result views
  https://app.notion.com/p/3e6d125495bf8142a1f8c14136dd0816
- Implement Marketplace overview request states
  https://app.notion.com/p/3e6d125495bf8177977af3621a16a319

Partly complete these Notion stories, which still have open items:
- Define and implement the Marketplace selector
  https://app.notion.com/p/3d1d125495bf8177876ee8ad9b3980c7
- Build the Marketplace overview search control
  https://app.notion.com/p/3cbd125495bf81ba8244e7ea0f1614ca
- Add Previous and Next pagination with URL state
  https://app.notion.com/p/3cbd125495bf81c68080f43491b5ffd5
- Load a selected Skill by slug
  https://app.notion.com/p/3cbd125495bf8112b493f2b6afb81bd2

Update the ADR for this Notion story:
- Record the Marketplace frontend architecture
  https://app.notion.com/p/3cbd125495bf81dbbe91c714a97ddab0
- Replace the header Back button, which #340 removed, with a back link
  on the Skill page
- Show the link above the Skill, the failed-load message, and the
  not-found message, so that it returns to the same overview results
  (PRD FR-17)
- Add the link to the Skill page skeleton
- Update the frontend ADR

Partly complete this Notion story (Marketplace Frontend Backlog):
- Load a selected Skill by slug
  https://app.notion.com/p/3cbd125495bf8112b493f2b6afb81bd2
Cancel superseded requests and debounced searches on browser history
navigation. Retain the loaded Marketplace list when Skills fail, so users
can select another source without showing an unverified empty state.

Encode opaque Skill slugs, decode their breadcrumb labels, and align
fixture search with the name-only contract. Promote ViewToggle to Terra
and commit routing, preferences, BFF, and browse regression coverage.

References: docs/adr/2026-08-17-agent-marketplace-frontend-architecture.md
Validation: make check CI=1 (844 unit, 213 integration, 358 Terra tests).
…earch in code points

The upstream client sends one keys parameter per favourite, so a path
holding a comma stays one key (C8); the e2e stand-in reads them with
getAll. The three-character search minimum counts code points, as
skills-service counts runes (C9).
The three-character hint and toSearch share one searchLength helper, so
typing two emoji shows the hint instead of doing nothing.
… card descriptions

Hades gains the approved link icon (D74). Each skill card's bottom bar has
an icon-only Copy link button, sized like the heart, with a tooltip and a
brief copied state; it copies the skill page's absolute address and does
not open the card. The skill page header has a Copy link button beside
View source. The card link reads View details.

Card descriptions clamp to three lines with the list view's clamp, now
one shared clampLines (D75); the skill page keeps the full text. The
story fixtures carry a long claude-api description.
A SKILL.md that is not text, or longer than its tree size, reads the same on
every crawl, so it no longer marks the list partial and forces a re-crawl at
each commit check. The cache error test no longer waits on client retries.
A skill left out by a crawl limit no longer marks the list partial: other
limits already force a crawl, so a limit-skipped list at an unchanged commit
is kept after one commit read. Ignore the skills-service build output like the
other cmd binaries.
SkillMarketplace gains a required spec.origin, internal or external, stating
whether the content is the organization's own or third-party (D76).
…etplaces

The aggregator writes spec.origin into each Marketplace entry, and
internal/platform/marketplace carries it to skills-service.
skills-service reads origin from kora-skill-marketplaces and returns it on
GET /v1/marketplaces items and the skill detail. An entry without a known
origin is skipped and logged, matching the required CRD field (D76).
The local fixture reads anthropics/skills, so it is external. The guide's
example-org Marketplace is internal, matching the ADR, and the guide lists the
field.
Marketplace and Skill carry origin: internal or external (D76). An
Internal (secondary) or External (outline) badge shows in each
Marketplace chip after the name, in each card footer before the
repository, from the Marketplace list the chips already load, and in an
Origin row of the skill page's Source card. FilterChip takes an optional
badge. The skill count beside the chips no longer wraps. Story and e2e
fixtures carry one internal and several external Marketplaces.
Hades swaps the link icon this PR added for share-2 (D78); nothing else
used link. The card button and the skill page button read Share, with
Link copied as the copied state, and still copy the skill page's address
without opening the card. The card button is now ShareButton.
…merges

Signed-off-by: Justin Wilkin <justin.wilkin@clearroute.io>
@justinwilkin
justinwilkin force-pushed the feat/skills-marketplace branch from df4a76a to c215a15 Compare November 5, 2026 04:22
@justinwilkin
justinwilkin added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 8b75d99 Nov 5, 2026
51 checks passed
@justinwilkin
justinwilkin deleted the feat/skills-marketplace branch November 5, 2026 21:02
@justinwilkin justinwilkin mentioned this pull request Nov 5, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants