Skip to content
Closed
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: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
.worktrees
*.tgz
7 changes: 5 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,11 @@ Examples:
return runCommand(target || null, { ...options, timeout: parseInt(options.timeout, 10) });
});

// List command (removed — use status instead)
program.command('list', { hidden: true }).description('[removed]').action(removedCommand('list', 'Use: squads status'));
// List command — alias for status
program.command('list').description('List squads (alias for: squads status)').action(async () => {
const { statusCommand } = await import('./commands/status.js');
return statusCommand();
});

// Orchestrate command - lead-coordinated squad execution
registerOrchestrateCommand(program);
Expand Down
94 changes: 93 additions & 1 deletion src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,44 @@ async function fileExists(filePath: string): Promise<boolean> {
}
}

/**
* Detect the primary technology stack from project files.
*/
async function detectStack(cwd: string): Promise<string> {
const checks: Array<[string, string]> = [
['package.json', 'node'],
['requirements.txt', 'python'],
['pyproject.toml', 'python'],
['setup.py', 'python'],
['go.mod', 'go'],
['Cargo.toml', 'rust'],
['pom.xml', 'java'],
['build.gradle', 'java'],
['Gemfile', 'ruby'],
['composer.json', 'php'],
];

for (const [file, stack] of checks) {
try {
await fs.access(path.join(cwd, file));
return stack;
} catch {
// not present
}
}
return 'unknown';
}

/**
* Slugify a name for use as a file/service identifier.
*/
function toServiceSlug(name: string): string {
return name
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '') || 'service';
}

/**
* Load a seed template from templates/seed/
* Falls back to bundled templates in dist/templates/seed/
Expand Down Expand Up @@ -471,10 +509,13 @@ export async function initCommand(options: InitOptions): Promise<void> {

// 5. Create the seed
const spinner = ora('Planting the seed...').start();
const serviceSlug = toServiceSlug(businessName);

try {
// Only show PLACEHOLDER sentinel when user skipped the description in interactive mode
const isPlaceholder = businessDescription.includes('add your business description');
const detectedStack = await detectStack(cwd);
const repoUrl = gitStatus.remoteUrl || '';
const variables: TemplateVariables = {
BUSINESS_NAME: businessName,
BUSINESS_DESCRIPTION: businessDescription || `${businessName} — details to be added by the manager agent.`,
Expand All @@ -488,6 +529,9 @@ export async function initCommand(options: InitOptions): Promise<void> {
PROVIDER: selectedProvider,
PROVIDER_NAME: provider?.name || 'Unknown',
CURRENT_DATE: new Date().toISOString().split('T')[0],
SERVICE_NAME: serviceSlug,
SERVICE_STACK: detectedStack,
REPO_URL: repoUrl,
};

// Core directories (always created)
Expand All @@ -511,6 +555,7 @@ export async function initCommand(options: InitOptions): Promise<void> {
'.agents/skills/squads-cli',
'.agents/skills/gh',
'.agents/config',
'.agents/idp/catalog',
];

// Add use-case specific directories
Expand Down Expand Up @@ -612,6 +657,51 @@ export async function initCommand(options: InitOptions): Promise<void> {
const businessBrief = loadSeedTemplate('BUSINESS_BRIEF.md.template', variables);
await writeFile(path.join(cwd, '.agents/BUSINESS_BRIEF.md'), businessBrief);

// company.md (L1 context layer — "Why" for all agents)
const companyMd = loadSeedTemplate('company.md', variables);
await writeIfNew(path.join(cwd, '.agents/company.md'), companyMd);

// IDP service catalog entry (only if .agents/idp/ doesn't already exist)
const idpCatalogFile = path.join(cwd, `.agents/idp/catalog/${serviceSlug}.yaml`);
const idpAlreadyExists = await fileExists(path.join(cwd, '.agents/idp/catalog'));
// Check if ANY yaml already exists — skip catalog generation if so
let existingCatalog = false;
if (idpAlreadyExists) {
try {
const entries = await fs.readdir(path.join(cwd, '.agents/idp/catalog'));
existingCatalog = entries.some(f => f.endsWith('.yaml'));
} catch {
// ignore
}
}
if (!existingCatalog) {
const catalogContent = loadSeedTemplate('idp/catalog/service.yaml', variables);
await writeFile(idpCatalogFile, catalogContent);
}

// priorities.md + goals.md — one per squad (writeIfNew so re-runs don't clobber)
const coreSquadNames = [
{ name: 'company', title: 'Company' },
{ name: 'research', title: 'Research' },
{ name: 'intelligence', title: 'Intelligence' },
{ name: 'product', title: 'Product' },
];
const useCaseSquadNames = useCaseConfig.squads.map(s => ({
name: s.name,
title: s.name.charAt(0).toUpperCase() + s.name.slice(1),
}));
for (const squad of [...coreSquadNames, ...useCaseSquadNames]) {
const squadVars = { ...variables, SQUAD_NAME: squad.name, SQUAD_NAME_TITLE: squad.title };
await writeIfNew(
path.join(cwd, `.agents/memory/${squad.name}/priorities.md`),
loadSeedTemplate('memory/squad-priorities.md', squadVars)
);
await writeIfNew(
path.join(cwd, `.agents/memory/${squad.name}/goals.md`),
loadSeedTemplate('memory/squad-goals.md', squadVars)
);
}

// AGENTS.md (repo root — vendor-neutral agent instructions)
const agentsMd = loadTemplate('core/AGENTS.md.template', variables);
await writeIfNew(path.join(cwd, 'AGENTS.md'), agentsMd);
Expand Down Expand Up @@ -703,7 +793,9 @@ export async function initCommand(options: InitOptions): Promise<void> {
}

writeLine(chalk.dim(' • .agents/skills/ CLI + GitHub workflow skills'));
writeLine(chalk.dim(' • .agents/memory/ Persistent state'));
writeLine(chalk.dim(' • .agents/memory/ Persistent state (goals, priorities per squad)'));
writeLine(chalk.dim(' • .agents/company.md Company context (L1 — the "why")'));
writeLine(chalk.dim(` • .agents/idp/catalog/ Service catalog — ${serviceSlug}.yaml`));
writeLine(chalk.dim(' • .agents/BUSINESS_BRIEF.md'));
writeLine(chalk.dim(' • AGENTS.md Agent instructions (vendor-neutral)'));
if (selectedProvider === 'claude') {
Expand Down
5 changes: 3 additions & 2 deletions src/lib/setup-checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,12 +260,13 @@ export function checkProviderAuth(providerId: string): CheckResult {
return { name: provider.name, status: 'ok' };
}

// Check CLI if required
// Check CLI if required — missing CLI is a warning (not an error) during init
// Users can scaffold first and install the provider CLI later
if (provider.cliCheck) {
if (!commandExists(provider.cliCheck)) {
return {
name: provider.name,
status: 'missing',
status: 'warning',
message: `CLI not installed`,
hint: provider.installCmd ? `Install: ${provider.installCmd}` : undefined,
fixCommand: provider.installCmd,
Expand Down
26 changes: 26 additions & 0 deletions templates/seed/company.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
scope: all-agents
authority: company
updated: {{CURRENT_DATE}}
---

# Company Context

## Mission

{{BUSINESS_DESCRIPTION}}

## What We Build

{{BUSINESS_NAME}} — see `.agents/BUSINESS_BRIEF.md` for details.

## Research Focus

{{BUSINESS_FOCUS}}

## How We Work

- Agents commit all output — if it's not in git, it didn't happen
- Every claim needs a source; outputs must be actionable
- Read state before acting; write state after
- Escalate to human when spend > $50 or scope is unclear
6 changes: 6 additions & 0 deletions templates/seed/config/SYSTEM.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
---
scope: all-agents
authority: immutable
version: "1.0"
---

# System Protocol

Immutable rules for all agent executions. Every agent reads this before starting work.
Expand Down
29 changes: 29 additions & 0 deletions templates/seed/idp/catalog/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Service catalog entry — auto-generated by squads init
# Edit this file to describe your service accurately.
# Docs: https://agents-squads.com/docs/idp/catalog

apiVersion: squads/v1
kind: Service
metadata:
name: {{SERVICE_NAME}}
description: {{BUSINESS_DESCRIPTION}}
owner: {{BUSINESS_NAME}}
repo: {{REPO_URL}}
tags:
- {{SERVICE_STACK}}
spec:
type: product
stack: {{SERVICE_STACK}}
branches:
default: main
development: develop
workflow: pr-to-develop
ci:
template: null
required_checks: []
test_command: null
build_command: null
health: []
dependencies:
runtime: []
scorecard: default
18 changes: 18 additions & 0 deletions templates/seed/memory/squad-goals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
squad: {{SQUAD_NAME}}
updated: {{CURRENT_DATE}}
---

# {{SQUAD_NAME_TITLE}} Goals

## Active

(No active goals yet — add them as your squad starts working)

## Achieved

(none yet)

## Abandoned

(none yet)
22 changes: 22 additions & 0 deletions templates/seed/memory/squad-priorities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
squad: {{SQUAD_NAME}}
updated: {{CURRENT_DATE}}
---

# {{SQUAD_NAME_TITLE}} Priorities

## Focus

1. **Deliver visible output on every run** — no run should end with nothing committed or noted
2. **Build on context** — read state.md before starting; don't repeat work already done

## Not Now

- Work outside squad scope
- Speculative improvements without clear business value

## Standing Rules

- Read `.agents/memory/{{SQUAD_NAME}}/*/state.md` before starting
- Write state.md after every run, even if nothing changed
- Every output must answer: "So what? What should we do next?"
3 changes: 3 additions & 0 deletions templates/seed/squads/company/company-critic.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Company Critic
role: critic
squad: company
provider: {{PROVIDER}}
trigger: manual
model: sonnet
effort: medium
tools:
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/company/company-eval.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Company Evaluator
role: evaluator
squad: company
provider: {{PROVIDER}}
trigger: manual
model: sonnet
effort: medium
tools:
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/company/event-dispatcher.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Event Dispatcher
role: doer
squad: company
provider: {{PROVIDER}}
trigger: manual
model: haiku
effort: medium
tools:
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/company/goal-tracker.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Goal Tracker
role: doer
squad: company
provider: {{PROVIDER}}
trigger: manual
model: haiku
effort: medium
tools:
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/company/manager.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Manager
role: lead
squad: company
provider: {{PROVIDER}}
trigger: manual
model: sonnet
effort: high
skills:
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/engineering/code-reviewer.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Code Reviewer
role: evaluator
squad: engineering
provider: {{PROVIDER}}
trigger: manual
model: sonnet
effort: medium
---
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/engineering/issue-solver.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Issue Solver
role: lead
squad: engineering
provider: {{PROVIDER}}
trigger: manual
model: sonnet
effort: high
skills:
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/engineering/test-writer.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Test Writer
role: doer
squad: engineering
provider: {{PROVIDER}}
trigger: manual
model: haiku
effort: medium
---
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/intelligence/intel-critic.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Intel Critic
role: critic
squad: intelligence
provider: {{PROVIDER}}
trigger: manual
model: haiku
effort: medium
tools:
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/intelligence/intel-eval.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Intel Eval
role: evaluator
squad: intelligence
provider: {{PROVIDER}}
trigger: manual
model: haiku
effort: medium
tools:
Expand Down
3 changes: 3 additions & 0 deletions templates/seed/squads/intelligence/intel-lead.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
name: Intel Lead
role: lead
squad: intelligence
provider: {{PROVIDER}}
trigger: manual
model: sonnet
effort: high
tools:
Expand Down
Loading
Loading