Scan
As your workspace grows, new repos get cloned but not always added to your config file. Skills, agents, and steering files get created inside editor-specific folders but never promoted to the canonical skills/, agents/, or steering/ directories. MCP servers get added directly to editor configs without being declared in your hub config. The hub scan command finds all of them for you.
What it does
hub scan performs three passes:
1. Unregistered repositories
Walks the workspace root looking for directories that contain a .git folder but aren’t listed in your config. For each one it:
- Detects the tech stack by checking for framework-specific files (
mix.exs→ Elixir,nest-cli.json→ NestJS,next.config.*→ Next.js, etc.) - Reads the git remote URL
- For YAML configs: offers to add them to
hub.yaml - For TypeScript configs: shows the suggested
repo.*()helper call to add manually
2. Unsynced assets
Scans editor-specific directories (.kiro, .cursor, .opencode, .claude) for skills, agents, and steering files that don’t exist in the canonical hub folders (skills/, agents/, steering/). For each unsynced asset it:
- Identifies the type (skill, agent, or steering) and source editor
- Offers to copy them to the canonical location
- Strips front-matter during the copy so files are editor-agnostic
This ensures that assets created in one editor are available to all editors after the next hub generate.
3. Unsynced MCP servers
Scans editor-specific MCP config files for servers not declared in your hub config:
| Editor | Config file | Key |
|---|---|---|
| Cursor | .cursor/mcp.json | mcpServers |
| Kiro | .kiro/settings/mcp.json | mcpServers |
| Claude Code | .mcp.json | mcpServers |
| OpenCode | opencode.json | mcp |
MCP servers found in editor configs but missing from your hub config are reported so you can add them manually (since MCPs require package, url, or image fields that can’t be inferred).
Usage
# Interactive — choose which repos and assets to sync
hub scan
# Auto-add and sync everything without prompting
hub scan --yes
# Check only — exit 1 if unsynced repos or assets are found
hub scan --check
| Flag | Description |
|---|---|
-y, --yes | Add all found repos and sync all assets without prompting |
--check | Check for unsynced repos and assets without prompting. Exits with code 1 if any are found, 0 if all synced. Useful in CI and pre-commit hooks. |
Example
$ hub scan
Scanning for unregistered repositories...
Found 2 unregistered repo(s):
notifications-service (nestjs)
admin-dashboard (nextjs)
? Select repos to add to hub.yaml:
◉ notifications-service (nestjs)
◉ admin-dashboard (nextjs)
Added 2 repo(s) to hub.yaml.
Scanning for unsynced skills, agents, steering, and MCPs...
Found 4 unsynced asset(s):
my-custom-skill (skill from .cursor)
pr-review.md (agent from .kiro)
code-standards.md (steering from .cursor)
my-new-mcp (mcp from .kiro)
? Select assets to sync to canonical folders:
◉ my-custom-skill (skill from .cursor)
◉ pr-review.md (agent from .kiro)
◉ code-standards.md (steering from .cursor)
◉ my-new-mcp (mcp from .kiro)
Synced skill: my-custom-skill (from .cursor)
Synced agent: pr-review.md (from .kiro)
Synced steering: code-standards.md (from .cursor)
MCP 'my-new-mcp' found in .kiro but not in hub.yaml — add it manually.
Synced 4 asset(s).
Run hub generate to update editor configs.
How it works
Repository scanning
For YAML configs, the scan preserves your existing hub.yaml formatting. Instead of parsing and re-serializing the YAML (which would lose comments and ordering), it finds the end of the repos: array and inserts new entries as raw text.
For TypeScript configs (hub.config.ts), the scan cannot auto-modify the file. Instead, it prints the suggested repo.*() helper call for each detected repo:
Found new repo: payments (nestjs)
→ Add to hub.config.ts: repo.nestjs("payments", "git@github.com:company/payments.git")
Each added repo (YAML) gets the minimal fields:
- name: notifications-service
path: ./notifications-service
url: git@github.com:company/notifications-service.git
tech: nestjs
Asset syncing
For each editor directory, the scan checks:
| Source | Asset type | Canonical destination |
|---|---|---|
.kiro/skills/, .cursor/skills/, .opencode/skills/, .claude/skills/ | Skill | skills/<name>/ |
.kiro/agents/, .cursor/agents/, .opencode/agents/, .claude/agents/ | Agent | agents/<name>.md |
.kiro/steering/ | Steering | steering/<name>.md |
.cursor/rules/ (.mdc files) | Steering | steering/<name>.md |
.opencode/rules/ | Steering | steering/<name>.md |
.cursor/mcp.json, .kiro/settings/mcp.json, .mcp.json, opencode.json | MCP | Reported only (add to hub.yaml manually) |
Auto-generated files like orchestrator.md and hub-docs are skipped.
After scanning, run hub generate to regenerate editor configs with the new repos and assets.
Tech detection
| File detected | Tech assigned |
|---|---|
mix.exs | elixir |
next.config.js/ts/mjs | nextjs |
nest-cli.json | nestjs |
angular.json | angular |
svelte.config.js | svelte |
nuxt.config.ts/js | vue |
go.mod | go |
Gemfile | rails |
manage.py | django |
package.json (fallback) | react |
Ignored directories
The scan skips common non-repo directories: node_modules, dist, build, .cache, tasks, agents, skills, memories, docs, scripts, and editor config folders (.cursor, .kiro, .vscode, etc.).