Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/eval-n8n.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ on:
datasets:
description: 'Comma-separated dataset paths (default: all golden datasets)'
required: false
default: 'evals/critical.json,evals/test-generation.json,evals/mutation.json,evals/fuzzing.json,evals/property.json,evals/quality-gate.json'
default: 'evals/critical.json,evals/test-generation.json,evals/mutation.json,evals/fuzzing.json,evals/property.json,evals/quality-gate.json,evals/three-arm-example.json,evals/skill-code.json,evals/skill-debug.json,evals/skill-github.json'
min_pass_rate:
description: 'Minimum pass rate (0.0..1.0)'
required: false
Expand All @@ -45,7 +45,7 @@ jobs:
echo "::error::N8N_CI_WEBHOOK_URL secret is not configured"
exit 1
fi
DATASETS="${{ inputs.datasets || 'evals/critical.json,evals/test-generation.json,evals/mutation.json,evals/fuzzing.json,evals/property.json,evals/quality-gate.json' }}"
DATASETS="${{ inputs.datasets || 'evals/critical.json,evals/test-generation.json,evals/mutation.json,evals/fuzzing.json,evals/property.json,evals/quality-gate.json,evals/three-arm-example.json,evals/skill-code.json,evals/skill-debug.json,evals/skill-github.json' }}"
curl -fsS -X POST \
-H "Content-Type: application/json" \
-d "{\"workflow\":\"eval-n8n\",\"ref\":\"${{ github.ref }}\",\"sha\":\"${{ github.sha }}\",\"repo\":\"${{ github.repository }}\",\"actor\":\"${{ github.actor }}\",\"datasets\":\"$DATASETS\",\"min_pass_rate\":\"${{ inputs.min_pass_rate || '0.8' }}\"}" \
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/eval-n8n.yml.doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Default datasets:
- `evals/fuzzing.json`
- `evals/property.json`
- `evals/quality-gate.json`
- `evals/three-arm-example.json` — canonical four-arm bench (issue #171)
- `evals/skill-code.json` — four-arm eval for code-skills (build, refactor, plan)
- `evals/skill-debug.json` — four-arm eval for debug-skills (deep RCA)
- `evals/skill-github.json` — four-arm eval for github-skills (actions, readme)

## Trigger

Expand All @@ -35,7 +39,7 @@ Default datasets:
"sha": "<commit-sha>",
"repo": "OpenSIN-Code/SIN-Code",
"actor": "<github-user>",
"datasets": "evals/critical.json,evals/test-generation.json,evals/mutation.json,evals/fuzzing.json,evals/property.json,evals/quality-gate.json",
"datasets": "evals/critical.json,evals/test-generation.json,evals/mutation.json,evals/fuzzing.json,evals/property.json,evals/quality-gate.json,evals/three-arm-example.json,evals/skill-code.json,evals/skill-debug.json,evals/skill-github.json",
"min_pass_rate": "0.8"
}
```
Expand Down
8 changes: 7 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ Skills ported from external repos (e.g. `Infra-SIN-OpenCode-Stack`,
### Skill distribution to external agents (issue #169)

`sin-code skill install <name> --agent <target>` distributes a bundled
Skill artifact to one of eight registered agent families. The single
Skill artifact to one of eleven registered agent families. The single
source of truth is `cmd/sin-code/internal/skilldist/Targets`:

| Target | Format | Install path template (relative to `$SIN_CODE_HOME`) |
Expand All @@ -695,6 +695,9 @@ source of truth is `cmd/sin-code/internal/skilldist/Targets`:
| `windsurf` | `rule` | `.windsurf/rules/<skill>.md` |
| `cline` | `rule` | `.clinerules/<skill>.md` |
| `copilot` | `marker` | `.github/copilot-instructions.md` |
| `aider` | `rule` | `.aider/conventions/<skill>.md` |
| `continue` | `rule` | `.continue/rules/<skill>.md` |
| `zed` | `rule` | `.zed/rules/<skill>.md` |

**Marker-fence contract.** Every write for `rule` and `marker` Formats
goes through `ParseMarkers` so a subsequent install with the same
Expand Down Expand Up @@ -773,6 +776,9 @@ sync if the table moves.
| windsurf | rule | `.windsurf/rules/sin-code.md` |
| cline | rule | `.clinerules/sin-code.md` |
| copilot | marker | `.github/copilot-instructions.md` |
| aider | rule | `.aider/conventions/sin-code.md` |
| continue | rule | `.continue/rules/sin-code.md` |
| zed | rule | `.zed/rules/sin-code.md` |

The four marker-fence outputs (`rule` + `marker`) wrap the body in
`<!-- SIN-CODE-SKILL-START: sin-code -->` … `<!-- SIN-CODE-SKILL-END: sin-code -->`
Expand Down
58 changes: 53 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,59 @@

All notable changes to the SIN-Code unified binary will be documented in this file.

<<<<<<< HEAD
## [v3.20.0] - 2026-06-17
## [Unreleased]

### Added — SOTA Skill Infrastructure

- **Skill frontmatter standardization**: All 36 bundled skills now have
filled `compatibility:` (sin-code, opencode, claude-code, codex) and
`metadata:` (author, version 3.20.0) frontmatter fields. The validator
(`scripts/validate_skill.py`) enforces `required_tools` as a YAML list
in `--strict` mode.
- **`required_tools` frontmatter field**: 8 key skills now declare their
required SIN tools (e.g. `skill-code-build` requires `sin_edit`,
`sin_test`, `sin_quality_gate`). Parsed at runtime by
`cmd/sin-code/internal/skillmgr/required_tools.go` and merged additively
(deduplicated, sorted) into `agentloop.Loop.CoverageRequiredTools` via
`loopbuilder.Config.ActiveSkills`. When a skill is activated, the
`ToolCoverageEnforcer` (issue #248) rejects task completion if the
required tools were not invoked. 17 race-clean tests.
- **3 new skilldist targets**: `aider` (`.aider/conventions/<skill>.md`,
rule format), `continue` (`.continue/rules/<skill>.md`, rule format),
`zed` (`.zed/rules/<skill>.md`, rule format). Total targets: 8 → 11.
Non-breaking (adding targets is allowed per AGENTS.md §10).
- **3 new skilldist targets in profile distribution**: `aider`, `continue`,
`zed` added to `cmd/sin-code/internal/profile/target.go` with
`sin-code.md` profile paths. Profile tests updated.
- **3 skill eval datasets**: `evals/skill-code.json` (3 cases: build /
refactor / plan), `evals/skill-debug.json` (2 cases: race / nil-pointer
RCA), `evals/skill-github.json` (2 cases: actions / readme). All
four-arm comparator compatible (baseline / terse / lazy_skill /
target-skill). Wired into `.github/workflows/eval-n8n.yml` n8n-delegated
CI (mandate M1).

### Fixed — Skill Validation

- **`skill-github-governance`**: `lifecycle: external` was nested under
`metadata:` instead of top-level frontmatter — validator rejected it
in `--strict` mode. Fixed: `lifecycle` is now a top-level key.
- **`skill-github-readme`**: `lifecycle: external` nesting issue (same as
governance). Additionally, `context/`, `frameworks/`, `tasks/`,
`templates/` directories were empty — validator flagged them in strict
mode. Fixed: all four directories now contain `.md` files with triggers,
standards, workflow, and templates.
- **`skill-code-create`**: Version references updated from v3.17.0 →
v3.20.0, skill count 34 → 36, frontmatter `compatibility` + `metadata`
filled. External duplicate `~/.config/opencode/skills/skill-create/`
removed.

### Updated — AGENTS.md §10

- Skill distribution table: 8 → 11 targets (aider, continue, zed added).
- Profile distribution table: 8 → 11 targets.
- CLI `--agent` flag help text and doc comments updated.

### Added — SIN Fusion v1: Verify-Tournament (issue #290)

The largest release in SIN-Code history. Two epics (21 issues), ~50 new
features, ~500 new tests, 33.5K lines of TUI code. Every test passes
Expand Down Expand Up @@ -388,9 +439,6 @@ gate (M3).
- go-echarts/v2 dependency — replaced with direct ECharts JSON generation (zero external charting deps)
- `--theme` flag from `image-graph` command (fixed dark theme, flag was dead)

## [Unreleased] - 2026-06-16
>>>>>>> 829b6f9 (chore: parallel cleanup — AGENTS.md counts, dead flag, CHANGELOG, bundle skill-code-graph)

### Added — SIN Fusion v1: Verify-Tournament (issue #290)
- **`internal/fusion/`** — new package: multi-model verify-tournament for verify-fail recovery
- When the sacred verify-gate (M3) fails, the task is fanned out to N Fireworks models in parallel (MiniMax M3, Kimi K2.7 Code Fast, Kimi K2.7 Code, DeepSeek V4 Pro, Qwen 3.7 Plus, GLM 5.2). First PoC-pass wins; losers cancelled via `context.WithCancel`
Expand Down
29 changes: 26 additions & 3 deletions cmd/sin-code/chat_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ import (
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/hooks"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/isolation"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/llm"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/logger"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/loopbuilder"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/mcpclient"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/orchestrator"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/permission"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/session"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/skillmgr"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/verify"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/logger"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/tui"
"github.com/OpenSIN-Code/SIN-Code/skills"
)

// chat hook variables — injected by coverage tests to avoid real I/O, network
Expand Down Expand Up @@ -107,8 +109,8 @@ type chatOptions struct {
// `plan | acceptEdits | bypass | default` automatically. The
// classifier is deterministic (regex + substring, no LLM) so
// M3 is honoured: every mode pick is operator-visible.
autolevel bool
lazyTools bool
autolevel bool
lazyTools bool
fusionOnVerifyFail bool
fusionProviders string
fusionMaxCost float64
Expand Down Expand Up @@ -365,6 +367,27 @@ func runChat(ctx context.Context, opts *chatOptions) error {
Ask: ask,
}

// Apply config-file defaults for tool coverage (issue #248) and merge
// required_tools from activated skills' SKILL.md frontmatter. The
// --activate list may contain skill names (e.g. "skill-code-build")
// whose required_tools are additive to any config-level constraints.
// Non-skill rule names are silently skipped by MergeRequiredTools.
{
coverageReq := loop.CoverageRequiredTools
if len(coverageReq) == 0 {
coverageReq = sinCfg.AgentLoopRequiredTools
}
if len(act.Rules) > 0 {
if skillFS, err := skills.ListFS(); err == nil {
coverageReq = skillmgr.MergeRequiredTools(coverageReq, act.Rules, skillFS)
}
}
loop.CoverageRequiredTools = coverageReq
if len(loop.CoverageForbiddenTools) == 0 {
loop.CoverageForbiddenTools = sinCfg.AgentLoopForbiddenTools
}
}

lazyTools := opts.lazyTools || sinCfg.ChatLazyTools || os.Getenv("SIN_LAZY_TOOLS") == "1"
if lazyTools {
loader := mcpclient.NewLazyToolLoader(allSpecsAsMCPClient(mcpMgr))
Expand Down
31 changes: 25 additions & 6 deletions cmd/sin-code/internal/loopbuilder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import (
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/orchestrator"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/permission"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/session"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/skillmgr"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/stopgate"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/style"
"github.com/OpenSIN-Code/SIN-Code/cmd/sin-code/internal/verify"
"github.com/OpenSIN-Code/SIN-Code/internal/headroom"
"github.com/OpenSIN-Code/SIN-Code/skills"
)

type Config struct {
Expand Down Expand Up @@ -71,17 +73,24 @@ type Config struct {
CoverageRequiredTools []string
CoverageForbiddenTools []string

// ActiveSkills lists skill names whose `required_tools` frontmatter
// field should be merged into CoverageRequiredTools (additive,
// deduplicated). The skills are looked up in the embedded
// skills.ListFS(). Non-skill rule names are silently skipped.
// See skillmgr.MergeRequiredTools (issue #248 skill activation path).
ActiveSkills []string

// SIN Fusion v1 (issue #290): when FusionEnabled is true and ≥2
// providers are available, a verify-tournament is wired into the
// loop. On verify.fail, the task is fanned out to N providers in
// parallel; the first to pass the PoC gate wins.
FusionEnabled bool
FusionProviders []string
FusionMaxCostUSD float64
FusionMinQuorum int
FusionEnabled bool
FusionProviders []string
FusionMaxCostUSD float64
FusionMinQuorum int
FusionPerProviderTimeoutS int
FusionDifficultyGate bool
FusionProfilesDir string
FusionDifficultyGate bool
FusionProfilesDir string

// DeepPlanner: when true, the orchestrator uses the parallel DAG
// DeepPlanner instead of the legacy linear Planner (issue #282).
Expand Down Expand Up @@ -148,6 +157,16 @@ func Build(ctx context.Context, cfg Config, memStore *lessons.Store) (*agentloop
}
}

// Merge required_tools from activated skills' SKILL.md frontmatter
// into CoverageRequiredTools (additive, deduplicated, sorted).
// Non-skill rule names in ActiveSkills are silently skipped.
if len(cfg.ActiveSkills) > 0 {
if skillFS, err := skills.ListFS(); err == nil {
cfg.CoverageRequiredTools = skillmgr.MergeRequiredTools(
cfg.CoverageRequiredTools, cfg.ActiveSkills, skillFS)
}
}

// Apply config-file defaults for SIN Fusion v1 (issue #290).
if !cfg.FusionEnabled {
if sinCfg, err := internal.LoadMergedConfig(); err == nil {
Expand Down
18 changes: 18 additions & 0 deletions cmd/sin-code/internal/profile/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,24 @@ var Targets = map[string]Target{
InstallPath: ".github/copilot-instructions.md",
Format: FormatMarker,
},
"aider": {
Name: "aider",
DisplayName: "Aider",
InstallPath: ".aider/conventions/sin-code.md",
Format: FormatRule,
},
"continue": {
Name: "continue",
DisplayName: "Continue",
InstallPath: ".continue/rules/sin-code.md",
Format: FormatRule,
},
"zed": {
Name: "zed",
DisplayName: "Zed",
InstallPath: ".zed/rules/sin-code.md",
Format: FormatRule,
},
}

// TargetNames returns every registered id in deterministic (alphabetical)
Expand Down
30 changes: 24 additions & 6 deletions cmd/sin-code/internal/skilldist/skilldist.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: MIT
// Package skilldist distributes a bundled SIN-Code Skill artifact to one of
// eight supported agent families: Claude Code, Codex, Gemini, opencode,
// Cursor, Windsurf, Cline, and GitHub Copilot. The package is the source of
// truth for the per-agent install path templates and is consumed exclusively
// by `cmd/sin-code/skill_cmd.go` (the `sin-code skill install --agent <id>`
// surface).
// eleven supported agent families: Claude Code, Codex, Gemini, opencode,
// Cursor, Windsurf, Cline, GitHub Copilot, Aider, Continue, and Zed. The
// package is the source of truth for the per-agent install path templates
// and is consumed exclusively by `cmd/sin-code/skill_cmd.go` (the
// `sin-code skill install --agent <id>` surface).
//
// # Marker-fenced idempotency
//
Expand Down Expand Up @@ -104,7 +104,7 @@ type Target struct {
// AGENTS.md §10 (the naming-and-stability matrix),
// CHANGELOG.md [Unreleased] (the additions bullet).
//
// The set is intentionally small (8 entries today). Verify-gated expansion
// The set is intentionally small (11 entries today). Verify-gated expansion
// is fine, but every new entry adds a maintenance row in three places.
var Targets = map[string]Target{
"claude-code": {
Expand Down Expand Up @@ -155,6 +155,24 @@ var Targets = map[string]Target{
InstallPath: ".github/copilot-instructions.md",
Format: FormatMarker,
},
"aider": {
Name: "aider",
DisplayName: "Aider",
InstallPath: ".aider/conventions/<skill>.md",
Format: FormatRule,
},
"continue": {
Name: "continue",
DisplayName: "Continue",
InstallPath: ".continue/rules/<skill>.md",
Format: FormatRule,
},
"zed": {
Name: "zed",
DisplayName: "Zed",
InstallPath: ".zed/rules/<skill>.md",
Format: FormatRule,
},
}

// TargetNames returns every registered id in deterministic (alphabetical)
Expand Down
4 changes: 2 additions & 2 deletions cmd/sin-code/internal/skilldist/skilldist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func allTargets() []Target {
// maintainer is forced through the policy update first.
func TestTargets_AllPresent(t *testing.T) {
want := []string{
"claude-code", "cline", "codex", "copilot",
"cursor", "gemini", "opencode", "windsurf",
"aider", "claude-code", "cline", "codex", "continue",
"copilot", "cursor", "gemini", "opencode", "windsurf", "zed",
}
got := TargetNames()
if !reflect.DeepEqual(got, want) {
Expand Down
Loading
Loading