maestro-dev — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited maestro-dev (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
maestroCLI follows hexagonal architecture. Every feature touches the same layers in the same order:
commands/ --> usecases/ --> ports/ <-- adapters/
(CLI I/O) (rules) (interfaces) (implementations)
server/ --> usecases/ --> ports/ <-- adapters/
(MCP I/O) (rules) (interfaces) (implementations)Commands and MCP server tools are thin I/O shells. Business logic lives in use-cases. Ports define what the system needs. Adapters provide it.
src/ports/)Ports are TypeScript interfaces that describe what the system needs without saying how to provide it. If your feature needs new persistence or external interaction, define it here.
// src/ports/memory.ts
export interface MemoryPort {
write(feature: string, name: string, content: string): Promise<void>;
read(feature: string, name: string): Promise<string | undefined>;
list(feature: string): Promise<string[]>;
delete(feature: string, name: string): Promise<void>;
compile(feature: string): Promise<string>;
}Rules:
src/adapters/)Adapters implement port interfaces against concrete backends (filesystem, beads_rust, etc.).
// src/adapters/fs/memory.ts
export class FsMemoryAdapter implements MemoryPort {
constructor(private directory: string) {}
async write(feature: string, name: string, content: string): Promise<void> {
const dir = join(this.directory, '.maestro', 'features', feature, 'memory');
await ensureDir(dir);
const filePath = join(dir, `${name}.md`);
await writeFileAtomic(filePath, content);
}
// ... other methods
}Rules:
Fs{Domain}Adapter for filesystem, Br{Domain}Adapter for beads_rustdirectory: string (project root)ensureDir() before writes, writeFileAtomic() for atomic I/O (temp + rename)MAX_PATH_LENGTH = 240src/adapters/ (flat files) or src/adapters/fs/ (filesystem-specific)src/usecases/)Use-cases contain business logic. They receive ports via the services singleton and orchestrate operations.
// src/usecases/check-status.ts
export async function checkStatus(
featureAdapter: FeaturePort,
taskPort: TaskPort,
planAdapter: PlanPort,
memoryAdapter: MemoryPort,
directory: string,
featureName?: string,
): Promise<FeatureStatus> {
const feature = featureName
? await featureAdapter.get(featureName)
: await featureAdapter.getActive();
if (!feature) throw new MaestroError('No active feature', ['Run: maestro feature-active <name>']);
// ... orchestrate across ports
}Rules:
MaestroError with actionable .hints[] arraysrc/commands/ or src/server/src/commands/<noun>/<verb>.ts)Commands are organized as noun/verb directories using citty's defineCommand.
// src/commands/memory/write.ts
import { defineCommand } from 'citty';
import { getServices } from '../../services.ts';
import { output } from '../../lib/output.ts';
export default defineCommand({
meta: { name: 'memory-write', description: 'Write a memory file for a feature' },
args: {
feature: { type: 'string', required: true, description: 'Feature name' },
name: { type: 'string', required: true, description: 'Memory file name' },
content: { type: 'string', required: true, description: 'Content to write' },
json: { type: 'boolean', default: false, description: 'Output as JSON' },
},
async run({ args }) {
const { memoryAdapter } = getServices();
await memoryAdapter.write(args.feature, args.name, args.content);
output(args.json, { feature: args.feature, name: args.name }, (r) => [
`[ok] Wrote memory: ${r.name} for feature: ${r.feature}`,
]);
},
});Rules:
src/commands/{noun}/{verb}.ts (e.g., memory/write.ts){noun}-{verb} (e.g., memory-write)json boolean arg for dual-mode outputgetServices() to access ports -- never instantiate adapters directlyoutput(isJson, data, textFormatter) for all outputMaestroError propagate -- the root command catches itsrc/server/)CLI commands are the primary surface. Each command calls a shared use-case function.
// In src/surfaces/cli/commands/memory-write.ts
export const memoryWrite = defineCommand({
name: 'memory-write',
description: 'Write a memory file for a feature',
args: {
feature: { type: 'string', describe: 'Feature name' },
name: { type: 'string', describe: 'Memory file name', required: true },
file: { type: 'string', describe: 'Path to content file', required: true },
},
}, async (args, services) => {
const content = readFileSync(args.file, 'utf-8');
await services.memoryAdapter.write(args.feature, args.name, content);
return { path: `Written: ${args.name}` };
});Rules:
kebab-case (hyphens, not underscores)--json for structured outputsrc/__tests__/)// src/__tests__/unit/memory.test.ts
import { describe, it, expect } from 'bun:test';
describe('FsMemoryAdapter', () => {
it('writes and reads a memory file', async () => {
const adapter = new FsMemoryAdapter(tmpDir);
await adapter.write('my-feature', 'notes', 'hello world');
const content = await adapter.read('my-feature', 'notes');
expect(content).toBe('hello world');
});
});Rules:
src/__tests__/unit/ -- test adapters and use-casessrc/__tests__/integration/ -- test CLI commandsbun:test (describe, it, expect)bun run build # Runs generators (skills registry, command registry) + bundles
bun test src/ # Runs all testsBuild must pass before proceeding. Tests must pass before committing.
All ports are wired in src/services.ts via a module-level singleton:
// Root command calls this once
initServices(directory);
// All commands and MCP tools call this
const { taskPort, memoryAdapter, featureAdapter, planAdapter } = getServices();The task backend is selected by config: configAdapter.get().taskBackend chooses between FsTaskAdapter (default) and BrTaskAdapter.
throw new MaestroError(
'Feature not found', // Title
['Run: maestro feature-list to see available features'] // Actionable hints
);Hints are printed line-by-line after the error title. Every error should tell the user what to do next.
Task and feature states use explicit transition maps:
const VALID_TRANSITIONS: Record<TaskStatus, TaskStatus[]> = {
open: ['claimed'],
claimed: ['done', 'blocked'],
blocked: ['open'],
done: [],
};Always validate transitions before applying them. Invalid transitions throw MaestroError.
getServices()console.log -- use output() for dual-mode JSON/textensureDir() first~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.