Skip to content

feat(init): add shared agents skills target - #1303

Merged
clay-good merged 2 commits into
Fission-AI:mainfrom
solanab:feat/init-agents-target
Jul 29, 2026
Merged

feat(init): add shared agents skills target#1303
clay-good merged 2 commits into
Fission-AI:mainfrom
solanab:feat/init-agents-target

Conversation

@solanab

@solanab solanab commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Status

Ready for review. Rebased onto current main (was 108 commits behind), all conflicts resolved, four adversarial reviews run and their findings fixed. Full suite green: 115 files / 3391 tests, plus tsc --noEmit and eslint clean.

What was missing

AI_TOOLS already carried an agents entry, but with available: false and no skillsDir — and every real gate keys off skillsDir, not available. So the option was unreachable everywhere: not in the picker, not via --tools, not in detection. Users wanting the shared .agents/skills root had to generate for some other tool and move files by hand.

What it does

openspec init --tools agents (and the interactive picker) installs the workflow skills to .agents/skills/openspec-*/SKILL.md, the vendor-neutral root modern agent tools read. It is skills-only — there is no cross-vendor slash-command format — so it follows the existing Kimi/Hermes adapterless pattern and reports Commands skipped for: agents (no adapter).

Two things beyond flipping the flag, both from review:

  • Detection is scoped to .agents/skills, not a bare .agents/. .agents/ is a generic root other frameworks create; detecting on it alone made non-interactive init silently install into a directory OpenSpec does not own, pre-checked agents in the picker, and produced a permanent Detected new tool nag on every update.
  • The entry was renamed to Shared .agents skills. The old label said "AGENTS.md", so the CLI printed Created: AGENTS.md (works with Amp, VS Code, …) while creating no such file — and OpenSpec in fact strips its markers out of a root AGENTS.md. That label was harmless while the entry was unreachable; this PR is what makes it user-visible.

Proof it works

Real output, openspec init --tools agents in an empty repo:

- Setting up Shared .agents skills...
✔ Setup complete for Shared .agents skills
Created: Shared .agents skills
6 skills in .agents/
Commands skipped for: agents (no adapter)
  Start your first change: /openspec-propose "your idea"

Verified in addition: update reports Tools: agents and refreshes the skills; a stale generatedBy correctly triggers agents (0.1.0 → 1.7.0); an unrelated .agents/my-framework/ no longer triggers detection; --tools all and antigravity (.agent) coexist without collision; delivery: commands degrades with a clear message; init/update are idempotent.

The change bundle also archives cleanly — verified end to end, including against a simulated main-side edit. It previously could not: every requirement sat under ## MODIFIED Requirements but none existed in the base specs, so openspec archive aborted. Restating the base requirements in full fixed that but introduced a worse problem — a MODIFIED block is a frozen copy, and the archive guard only detects dropped scenario names, not changed scenario bodies. I reproduced it: simulating a main-side correction to an unrelated scenario, validate --strict passed, archive reported success, and the correction was silently reverted. The deltas are now ## ADDED Requirements that copy no base text, so a main-side edit survives.

Related

Notes / nits

Summary by CodeRabbit

  • New Features

    • Added a first-class agents target for openspec init/updates that installs shared “AGENTS.md-compatible” workflow skills under .agents/skills.
    • agents is skills-only (no command adapters generated) and uses /openspec-<skill> syntax.
  • Bug Fixes

    • Improved detection so only .agents/skills enables the target; a bare .agents folder won’t select it.
    • The deprecated experimental --tool agents flow now succeeds and refreshes shared skills.
  • Documentation

    • Updated CLI help and guidance (supported tools, command syntax, and troubleshooting) to include agents (with windsurf kept as an alias).

@solanab
solanab requested a review from TabishB as a code owner July 4, 2026 03:33
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR enables agents as a first-class, adapterless openspec init/update skills target rooted at .agents, updates its specifications and documentation, and adds coverage for initialization, update, discovery, and the deprecated alias.

Changes

Generic agents installer target

Layer / File(s) Summary
Enable agents target and define paths
src/core/config.ts, openspec/changes/.../specs/ai-tool-paths/spec.md
Registers agents as available, stores skills under .agents, and limits detection to .agents/skills.
Specify and validate skills-only initialization
openspec/changes/.../specs/cli-init/spec.md, test/core/init.test.ts, test/core/update.test.ts, test/cli-e2e/basic.test.ts, test/commands/artifact-workflow.test.ts
Defines and tests skill generation without command files for initialization, update, and the deprecated alias.
Validate tool discovery
test/core/available-tools.test.ts, test/core/shared/tool-detection.test.ts, test/core/init.test.ts
Covers configured skills directories, .agents/skills detection, bare .agents exclusion, and unrelated ZCode initialization behavior.
Document and publish agents target
docs/cli.md, docs/supported-tools.md, docs/commands.md, docs/how-commands-work.md, docs/troubleshooting.md, .changeset/add-agents-tool.md
Documents the agents ID, .agents/skills/ output, skills-only invocation, detection behavior, and minor release metadata.
Record implementation change set
openspec/changes/add-init-agents-target/.openspec.yaml, openspec/changes/add-init-agents-target/proposal.md, openspec/changes/add-init-agents-target/specs/*, openspec/changes/add-init-agents-target/tasks.md
Adds change metadata, requirements, proposal, task checklist, and implementation scope for the shared target.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OpenSpecCLI
  participant AIToolsConfig
  participant ProjectFilesystem
  User->>OpenSpecCLI: Run init --tools agents
  OpenSpecCLI->>AIToolsConfig: Resolve agents target
  AIToolsConfig-->>OpenSpecCLI: .agents skills path, no command adapter
  OpenSpecCLI->>ProjectFilesystem: Write .agents/skills/openspec-explore/SKILL.md
  OpenSpecCLI-->>User: Report skipped commands for agents
Loading

Possibly related PRs

Suggested reviewers: tabishb, alfred-openspec

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning [#1104] is satisfied, but [#1480] requested .agents/commands too, and this PR only adds skills-only support. Add the .agents/commands generation path or update the linked issue scope; the current change only implements .agents/skills.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a shared agents skills target to init.
Out of Scope Changes check ✅ Passed The changes stay focused on the new .agents target across config, docs, specs, and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@clay-good
clay-good force-pushed the feat/init-agents-target branch from f247b43 to de4b0ba Compare July 29, 2026 18:07
@clay-good
clay-good requested a review from a team as a code owner July 29, 2026 18:07

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
test/commands/artifact-workflow.test.ts (1)

1131-1139: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the skills-only contract in this regression test.

This test would still pass if agents also generated command files. Assert the documented Commands skipped for: agents (no adapter) output and/or the absence of generated command files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/commands/artifact-workflow.test.ts` around lines 1131 - 1139, Update the
“creates skills for the shared agents target” test to assert the skills-only
contract: verify the CLI output includes “Commands skipped for: agents (no
adapter)” and confirm no command files are generated for the agents target,
while preserving the existing skill-file and successful-exit assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/supported-tools.md`:
- Around line 114-118: Update the “Your tool has its own row above” guidance in
the supported-tools table to say that selecting the tool’s own ID provides its
integration, with generated slash commands only where supported; do not promise
command files for every tool-specific target.

In `@openspec/changes/add-init-agents-target/specs/ai-tool-paths/spec.md`:
- Around line 19-22: Update the “Windsurf paths defined” scenario to reflect the
alias contract: describe lookup of the windsurf alias resolving to devin and
require skillsDir to be .devin, unless a dedicated Windsurf tool target is
intentionally restored as the primary configuration.

---

Nitpick comments:
In `@test/commands/artifact-workflow.test.ts`:
- Around line 1131-1139: Update the “creates skills for the shared agents
target” test to assert the skills-only contract: verify the CLI output includes
“Commands skipped for: agents (no adapter)” and confirm no command files are
generated for the agents target, while preserving the existing skill-file and
successful-exit assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3c899815-a6ac-40ae-b8b1-7ea23fa57612

📥 Commits

Reviewing files that changed from the base of the PR and between f247b43 and de4b0ba.

📒 Files selected for processing (14)
  • .changeset/add-agents-tool.md
  • docs/cli.md
  • docs/commands.md
  • docs/how-commands-work.md
  • docs/supported-tools.md
  • docs/troubleshooting.md
  • openspec/changes/add-init-agents-target/.openspec.yaml
  • openspec/changes/add-init-agents-target/proposal.md
  • openspec/changes/add-init-agents-target/specs/ai-tool-paths/spec.md
  • openspec/changes/add-init-agents-target/specs/cli-init/spec.md
  • openspec/changes/add-init-agents-target/tasks.md
  • src/core/config.ts
  • test/cli-e2e/basic.test.ts
  • test/commands/artifact-workflow.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • openspec/changes/add-init-agents-target/.openspec.yaml
  • openspec/changes/add-init-agents-target/tasks.md
  • test/cli-e2e/basic.test.ts
  • openspec/changes/add-init-agents-target/proposal.md

Comment thread docs/supported-tools.md
Comment on lines +19 to +22
#### Scenario: Windsurf paths defined

- **WHEN** looking up the `windsurf` tool
- **THEN** `skillsDir` SHALL be `.windsurf`

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Align the Windsurf scenario with the alias contract.

src/core/config.ts no longer registers windsurf as a tool; TOOL_ID_ALIASES resolves it to devin, whose primary skills directory is .devin. Update this scenario to describe the windsurf alias and .devin path, or retain a dedicated Windsurf target if .windsurf must remain primary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openspec/changes/add-init-agents-target/specs/ai-tool-paths/spec.md` around
lines 19 - 22, Update the “Windsurf paths defined” scenario to reflect the alias
contract: describe lookup of the windsurf alias resolving to devin and require
skillsDir to be .devin, unless a dedicated Windsurf tool target is intentionally
restored as the primary configuration.

@clay-good
clay-good force-pushed the feat/init-agents-target branch from de4b0ba to d59fd4d Compare July 29, 2026 18:13
@clay-good

Copy link
Copy Markdown
Collaborator

Addressed the CodeRabbit review:

  • docs/supported-tools.md — "you also get generated slash commands": valid, fixed. Reworded to "you get that tool's integration, including slash commands where it supports them." Several tools with their own row (Codex, CodeArts, ForgeCode, Hermes, Kimi Code, Mistral Vibe) are skills-only, so the original phrasing overpromised.

  • ai-tool-paths delta — Windsurf scenario: skipping, with a reason. That scenario is pre-existing text in openspec/specs/ai-tool-paths/spec.md on main, reproduced here verbatim and unmodifieddiff against origin/main is empty. It appears in this delta only because main's scenario-loss guard rejects a MODIFIED block that omits any existing scenario, so the block has to carry every one of them.

    The observation is correct on its merits — windsurf is now an alias resolving to devin with .devin, so that scenario is stale relative to the rename in feat(adapters): follow the Windsurf rename to Devin Desktop #1167. But it is stale on main today, independent of this PR, and correcting it here would silently amend an unrelated requirement inside a change whose stated scope is the shared .agents target. Better as its own follow-up.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/troubleshooting.md`:
- Line 62: Update the `.agents` entry in the “Confirm your tool supports command
files” guidance to avoid prescribing `/openspec-propose`; direct users to the
consuming tool’s documented skill invocation syntax instead. Keep the
vendor-specific invocation examples for Codex, Kimi Code, the other named tools,
and Amazon Q unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fb3a5621-16bc-4ece-81d5-0a8d6c5c5fb8

📥 Commits

Reviewing files that changed from the base of the PR and between 4e16790 and c8500a9.

📒 Files selected for processing (18)
  • .changeset/add-agents-tool.md
  • docs/cli.md
  • docs/commands.md
  • docs/how-commands-work.md
  • docs/supported-tools.md
  • docs/troubleshooting.md
  • openspec/changes/add-init-agents-target/.openspec.yaml
  • openspec/changes/add-init-agents-target/proposal.md
  • openspec/changes/add-init-agents-target/specs/ai-tool-paths/spec.md
  • openspec/changes/add-init-agents-target/specs/cli-init/spec.md
  • openspec/changes/add-init-agents-target/tasks.md
  • src/core/config.ts
  • test/cli-e2e/basic.test.ts
  • test/commands/artifact-workflow.test.ts
  • test/core/available-tools.test.ts
  • test/core/init.test.ts
  • test/core/shared/tool-detection.test.ts
  • test/core/update.test.ts
🚧 Files skipped from review as they are similar to previous changes (13)
  • openspec/changes/add-init-agents-target/.openspec.yaml
  • docs/commands.md
  • openspec/changes/add-init-agents-target/specs/cli-init/spec.md
  • test/cli-e2e/basic.test.ts
  • test/commands/artifact-workflow.test.ts
  • .changeset/add-agents-tool.md
  • openspec/changes/add-init-agents-target/proposal.md
  • openspec/changes/add-init-agents-target/specs/ai-tool-paths/spec.md
  • openspec/changes/add-init-agents-target/tasks.md
  • docs/how-commands-work.md
  • docs/cli.md
  • test/core/init.test.ts
  • src/core/config.ts

Comment thread docs/troubleshooting.md Outdated
@clay-good
clay-good force-pushed the feat/init-agents-target branch from c8500a9 to 5c24665 Compare July 29, 2026 18:42
@clay-good

Copy link
Copy Markdown
Collaborator

Addressed the latest CodeRabbit note.

Valid, fixed. /openspec-propose was written as a prescription for the shared .agents target, but that target is vendor-neutral by definition, so the syntax is the common form rather than a guaranteed one. docs/troubleshooting.md and the When to pick the shared .agents target section now say so, and point users at their assistant's own docs if it does not respond to /openspec-<skill>.

I kept .agents in the /openspec-<skill> row of the invoke tables rather than splitting it out: it is the form the overwhelming majority of skill-reading assistants use, and it is what OpenSpec's own setup hint prints after init --tools agents, so the tables stay accurate for the common case while the prose carries the caveat.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/commands.md`:
- Line 676: Update the skills-only row in the command support table so the
shared `.agents` target is not presented as universally supporting `/openspec-*`
slash commands. Qualify command availability as assistant-dependent or direct
readers to each assistant’s skill-invocation documentation, while preserving the
existing vendor entries.

In `@test/core/init.test.ts`:
- Line 223: Remove the duplicate logCalls const declaration in the final test
callback, keeping one shared declaration for the existing assertions and
preserving its current computation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 03aaf90c-66e3-413f-87a4-c250f265af5f

📥 Commits

Reviewing files that changed from the base of the PR and between c8500a9 and 5c24665.

📒 Files selected for processing (18)
  • .changeset/add-agents-tool.md
  • docs/cli.md
  • docs/commands.md
  • docs/how-commands-work.md
  • docs/supported-tools.md
  • docs/troubleshooting.md
  • openspec/changes/add-init-agents-target/.openspec.yaml
  • openspec/changes/add-init-agents-target/proposal.md
  • openspec/changes/add-init-agents-target/specs/ai-tool-paths/spec.md
  • openspec/changes/add-init-agents-target/specs/cli-init/spec.md
  • openspec/changes/add-init-agents-target/tasks.md
  • src/core/config.ts
  • test/cli-e2e/basic.test.ts
  • test/commands/artifact-workflow.test.ts
  • test/core/available-tools.test.ts
  • test/core/init.test.ts
  • test/core/shared/tool-detection.test.ts
  • test/core/update.test.ts
🚧 Files skipped from review as they are similar to previous changes (13)
  • openspec/changes/add-init-agents-target/.openspec.yaml
  • test/core/available-tools.test.ts
  • test/core/shared/tool-detection.test.ts
  • .changeset/add-agents-tool.md
  • openspec/changes/add-init-agents-target/specs/cli-init/spec.md
  • docs/cli.md
  • openspec/changes/add-init-agents-target/tasks.md
  • test/cli-e2e/basic.test.ts
  • openspec/changes/add-init-agents-target/proposal.md
  • test/commands/artifact-workflow.test.ts
  • docs/troubleshooting.md
  • src/core/config.ts
  • docs/how-commands-work.md

Comment thread docs/commands.md
| `.../commands/opsx/<id>.*` | `/opsx:propose`, `/opsx:apply` | Claude Code, Gemini CLI, Crush |
| `.../opsx-<id>.*` | `/opsx-propose`, `/opsx-apply` | Cursor, Devin Desktop, Copilot (IDE), Trae, Oh My Pi |
| none — skills only | `/openspec-propose`, `/openspec-apply-change` | CodeArts, ForgeCode, Hermes, Mistral Vibe |
| none — skills only | `/openspec-propose`, `/openspec-apply-change` | CodeArts, ForgeCode, Hermes, Mistral Vibe, shared `.agents` |

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not present shared .agents as universally supporting slash commands.

Because .agents is a vendor-neutral, skills-only target without a generic command adapter, this row may imply that /openspec-* syntax works in every assistant consuming .agents. Qualify the entry as assistant-dependent, or point readers to their assistant’s skill-invocation documentation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/commands.md` at line 676, Update the skills-only row in the command
support table so the shared `.agents` target is not presented as universally
supporting `/openspec-*` slash commands. Qualify command availability as
assistant-dependent or direct readers to each assistant’s skill-invocation
documentation, while preserving the existing vendor entries.

Comment thread test/core/init.test.ts
const commandsDir = path.join(testDir, '.agents', 'commands');
expect(await directoryExists(commandsDir)).toBe(false);

const logCalls = (console.log as unknown as { mock: { calls: unknown[][] } }).mock.calls.flat().map(String);

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.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Remove the duplicate logCalls declaration.

The final test contains two identical const logCalls declarations in the same callback scope, causing a TypeScript compilation error.

Proposed fix
       const commandsDir = path.join(testDir, '.agents', 'commands');
       expect(await directoryExists(commandsDir)).toBe(false);

-      const logCalls = (console.log as unknown as { mock: { calls: unknown[][] } }).mock.calls.flat().map(String);
       const logCalls = (console.log as unknown as { mock: { calls: unknown[][] } }).mock.calls.flat().map(String);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const logCalls = (console.log as unknown as { mock: { calls: unknown[][] } }).mock.calls.flat().map(String);
const commandsDir = path.join(testDir, '.agents', 'commands');
expect(await directoryExists(commandsDir)).toBe(false);
const logCalls = (console.log as unknown as { mock: { calls: unknown[][] } }).mock.calls.flat().map(String);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/core/init.test.ts` at line 223, Remove the duplicate logCalls const
declaration in the final test callback, keeping one shared declaration for the
existing assertions and preserving its current computation.

Source: Learnings

@clay-good
clay-good force-pushed the feat/init-agents-target branch 2 times, most recently from 5c24665 to a023ba5 Compare July 29, 2026 19:09

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The shared target is correctly scoped to .agents/skills, stays skills-only, preserves foreign content, and integrates cleanly with init, update, detection, and --tools all. Exact head a023ba5 passed the hosted CI/security matrix plus an isolated build and 316 focused tests.

@clay-good
clay-good self-requested a review July 29, 2026 22:41
@clay-good
clay-good added this pull request to the merge queue Jul 29, 2026
Merged via the queue into Fission-AI:main with commit 1aa0f2a Jul 29, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants