Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
dbd828d
feat(ide-sync): agent-native + skill-first migration [Story IDE-SKILL-1]
oalanicolas Feb 17, 2026
4a953f9
feat(ide): complete skills-first migration and improve task-skill met…
oalanicolas Feb 17, 2026
03d154f
chore(ids): update entity registry after skill sync
oalanicolas Feb 17, 2026
b704f91
feat(skills): enforce owner-agent preload in task skills
oalanicolas Feb 18, 2026
0f5b3e3
fix(agents): correct persona paths and sequential context loading
Pedrovaleriolopez Feb 18, 2026
d4adcac
refactor(agents): remove aios- prefix from .claude/agents filenames
Pedrovaleriolopez Feb 18, 2026
a0937fd
feat(agents): add per-agent always-load files, agent subdirectories, …
Pedrovaleriolopez Feb 19, 2026
de0e8b8
feat(agents): implement 3-layer architecture and defense-in-depth con…
Pedrovaleriolopez Feb 19, 2026
8a25287
feat(tasks): fix task-to-agent ownership mapping for 196 tasks [Story…
Pedrovaleriolopez Feb 19, 2026
f9fdf85
feat(agents): implement AGF-4 DNA/Enhancement split + SessionStart/Pr…
Pedrovaleriolopez Feb 20, 2026
49a0e73
docs(stories): update AGF-4 story to Ready for Review
Pedrovaleriolopez Feb 20, 2026
e06349f
fix(hooks): correct sed regex in pre-compact-persona hook [Story AGF-4]
Pedrovaleriolopez Feb 20, 2026
b4e82da
feat(hooks): implement SYNAPSE-Lite UserPromptSubmit + Stop hooks [St…
Pedrovaleriolopez Feb 20, 2026
72d6dea
feat(ide-sync): update codex/gemini agent definitions and skills-sync…
Pedrovaleriolopez Feb 20, 2026
36f9c2c
docs(stories): update AGF-4/AGF-5 stories with QA results and entity-…
Pedrovaleriolopez Feb 20, 2026
28fb557
fix(test): update onboarding-smoke greeting assertion for AGF-4 format
Pedrovaleriolopez Feb 20, 2026
c1c6993
fix(tests): resolve pipeline-memory and codex-skills-validate failure…
Pedrovaleriolopez Feb 20, 2026
7260721
refactor(AGF-6): deprecate UAP/greeting-builder, consolidate agent me…
Pedrovaleriolopez Feb 20, 2026
087ef54
docs(AGF-7): investigation report, tech search, ADR with 7 architectu…
Pedrovaleriolopez Feb 21, 2026
ad1b1cc
fix(security): eliminate supply chain risks from npx and shell execution
riaworks Feb 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
68 changes: 65 additions & 3 deletions .aios-core/core-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,56 @@ devLoadAlwaysFiles:
- docs/framework/coding-standards.md
- docs/framework/tech-stack.md
- docs/framework/source-tree.md
# Per-agent always-load files (loaded during activation)
# Purpose: rules, project context, boundaries — NOT domain knowledge.
# Domain-specific knowledge is loaded by tasks when needed.
agentAlwaysLoadFiles:
dev:
- docs/framework/coding-standards.md
- docs/framework/tech-stack.md
- docs/framework/source-tree.md
qa:
- docs/framework/coding-standards.md
- docs/framework/tech-stack.md
- docs/framework/source-tree.md
- .aios-core/product/data/test-levels-framework.md
- .aios-core/product/data/test-priorities-matrix.md
architect:
- docs/framework/tech-stack.md
- docs/framework/source-tree.md
- docs/architecture/agent-system-architecture.md
devops:
- docs/framework/coding-standards.md
- docs/framework/source-tree.md
- docs/architecture/command-authority-matrix.md
pm:
- docs/framework/source-tree.md
- docs/framework/tech-stack.md
- docs/stories/backlog.md
po:
- docs/framework/source-tree.md
- docs/stories/backlog.md
- docs/architecture/command-authority-matrix.md
sm:
- docs/framework/source-tree.md
- docs/stories/backlog.md
- docs/framework/coding-standards.md
analyst:
- docs/framework/tech-stack.md
- docs/framework/source-tree.md
data-engineer:
- docs/framework/tech-stack.md
- docs/framework/source-tree.md
ux-design-expert:
- docs/framework/tech-stack.md
- docs/framework/source-tree.md
- docs/framework/coding-standards.md
aios-master:
- .aios-core/constitution.md
- docs/framework/source-tree.md
- docs/architecture/command-authority-matrix.md
squad-creator:
- docs/framework/source-tree.md
devLoadAlwaysFilesFallback:
- docs/pt/framework/coding-standards.md
- docs/pt/framework/tech-stack.md
Expand Down Expand Up @@ -308,8 +358,12 @@ ideSync:
targets:
claude-code:
enabled: true
path: .claude/commands/AIOS/agents
format: full-markdown-yaml
path: .claude/agents
format: claude-native-agent
claude-skills:
enabled: true
path: .claude/skills
format: claude-agent-skill
codex:
enabled: true
path: .codex/agents
Expand All @@ -318,10 +372,14 @@ ideSync:
enabled: true
path: .gemini/rules/AIOS/agents
format: full-markdown-yaml
gemini-skills:
enabled: true
path: packages/gemini-aios-extension/skills
format: gemini-agent-skill
github-copilot:
enabled: true
path: .github/agents
format: full-markdown-yaml
format: github-copilot-native-agent
cursor:
enabled: true
path: .cursor/rules/agents
Expand All @@ -330,6 +388,10 @@ ideSync:
enabled: true
path: .antigravity/rules/agents
format: cursor-style
claude-commands:
enabled: true
path: .claude/commands/AIOS/agents
format: claude-command-wrapper
redirects: {}
validation:
strictMode: true
Expand Down
113 changes: 103 additions & 10 deletions .aios-core/core/ids/registry-updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
const lockfile = require('proper-lockfile');
let properLockfile = null;
try {
properLockfile = require('proper-lockfile');
} catch {
properLockfile = null;
}
const { RegistryLoader } = require(path.resolve(__dirname, 'registry-loader.js'));
const {
extractEntityId,
Expand All @@ -28,6 +33,7 @@ const LOCK_TIMEOUT_MS = 5000;
const LOCK_RETRY_COUNT = 3;
const LOCK_RETRY_DELAY_MS = 100;
const LOCK_STALE_MS = 10000;
const FALLBACK_LOCK_OWNER = `ids-registry-updater:${process.pid}`;

const WATCH_PATHS = SCAN_CONFIG.map((c) => c.basePath);

Expand Down Expand Up @@ -458,6 +464,89 @@ class RegistryUpdater {

// ─── Internal: File Locking ──────────────────────────────────────

_sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

_isFallbackLockStale() {
try {
const lockStat = fs.statSync(this._lockFile);
return (Date.now() - lockStat.mtimeMs) > LOCK_STALE_MS;
} catch (err) {
if (err.code === 'ENOENT') return true;
throw err;
}
}

_removeFallbackLockIfOwned(ownerToken) {
try {
const raw = fs.readFileSync(this._lockFile, 'utf8');
let parsed = null;
try {
parsed = JSON.parse(raw);
} catch {
parsed = null;
}

// Only remove if this process owns the lock token.
if (parsed && parsed.token && parsed.token !== ownerToken) {
return;
}

fs.unlinkSync(this._lockFile);
} catch (err) {
if (err.code === 'ENOENT') return;
throw err;
}
}

_removeFallbackStaleLock() {
try {
fs.unlinkSync(this._lockFile);
} catch (err) {
if (err.code === 'ENOENT') return;
throw err;
}
}

async _acquireFallbackLock() {
const ownerToken = `${FALLBACK_LOCK_OWNER}:${Date.now()}:${Math.random().toString(36).slice(2, 10)}`;

for (let attempt = 0; attempt <= LOCK_RETRY_COUNT; attempt++) {
try {
const payload = {
owner: FALLBACK_LOCK_OWNER,
pid: process.pid,
token: ownerToken,
acquiredAt: new Date().toISOString(),
};

fs.writeFileSync(this._lockFile, JSON.stringify(payload), { flag: 'wx', encoding: 'utf8' });

return async () => {
this._removeFallbackLockIfOwned(ownerToken);
};
} catch (err) {
if (err.code !== 'EEXIST') {
throw err;
}

if (this._isFallbackLockStale()) {
this._removeFallbackStaleLock();
continue;
}

if (attempt === LOCK_RETRY_COUNT) {
throw new Error(`fallback lock timeout after ${LOCK_RETRY_COUNT + 1} attempts`);
}

await this._sleep(LOCK_RETRY_DELAY_MS);
}
}

throw new Error('fallback lock acquisition failed');
}

async _withLock(operation) {
const lockDir = path.dirname(this._lockFile);
if (!fs.existsSync(lockDir)) {
Expand All @@ -470,15 +559,19 @@ class RegistryUpdater {

let release;
try {
release = await lockfile.lock(this._registryPath, {
stale: LOCK_STALE_MS,
retries: {
retries: LOCK_RETRY_COUNT,
minTimeout: LOCK_RETRY_DELAY_MS,
maxTimeout: LOCK_TIMEOUT_MS,
},
lockfilePath: this._lockFile,
});
if (properLockfile && typeof properLockfile.lock === 'function') {
release = await properLockfile.lock(this._registryPath, {
stale: LOCK_STALE_MS,
retries: {
retries: LOCK_RETRY_COUNT,
minTimeout: LOCK_RETRY_DELAY_MS,
maxTimeout: LOCK_TIMEOUT_MS,
},
lockfilePath: this._lockFile,
});
} else {
release = await this._acquireFallbackLock();
}
} catch (err) {
throw new Error(`[IDS-Updater] Could not acquire lock: ${err.message}`);
}
Expand Down
18 changes: 10 additions & 8 deletions .aios-core/core/manifest/manifest-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,32 +165,34 @@ class ManifestGenerator {
const errors = [];

try {
const files = await fs.readdir(agentsDir);
const mdFiles = files.filter(f => f.endsWith('.md'));
const entries = await fs.readdir(agentsDir, { withFileTypes: true });

for (const file of mdFiles) {
for (const entry of entries) {
if (!entry.isDirectory()) continue;
const candidate = path.join(agentsDir, entry.name, `${entry.name}.md`);
try {
const filePath = path.join(agentsDir, file);
const content = await fs.readFile(filePath, 'utf8');
const content = await fs.readFile(candidate, 'utf8');
const parsed = parseYAMLFromMarkdown(content);

if (parsed && parsed.agent) {
const agent = parsed.agent;
const persona = parsed.persona_profile || parsed.persona || {};

agents.push({
id: agent.id || file.replace('.md', ''),
id: agent.id || entry.name,
name: agent.name || 'Unknown',
archetype: persona.archetype || agent.title || 'Agent',
icon: agent.icon || '🤖',
version: this.version,
status: 'active',
file_path: `.aios-core/development/agents/${file}`,
file_path: `.aios-core/development/agents/${entry.name}/${entry.name}.md`,
when_to_use: agent.whenToUse || '',
});
}
} catch (e) {
errors.push(`Error parsing ${file}: ${e.message}`);
if (e.code !== 'ENOENT') {
errors.push(`Error parsing ${entry.name}: ${e.message}`);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion .aios-core/core/orchestration/skill-dispatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class SkillDispatcher {

/**
* Mapping from agent IDs to full Skill names
* These correspond to files in .claude/commands/AIOS/agents/
* These correspond to files in .aios-core/development/agents/
*/
this.skillMapping = {
// Core development agents
Expand Down
2 changes: 1 addition & 1 deletion .aios-core/core/quality-gates/quality-gate-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ layer2:
quinn:
enabled: true
autoReview: true
agentPath: ".claude/commands/AIOS/agents/qa.md"
agentPath: ".aios-core/development/agents/qa/qa.md"
severity:
block: ["CRITICAL"]
warn: ["HIGH", "MEDIUM"]
Expand Down
19 changes: 12 additions & 7 deletions .aios-core/core/synapse/diagnostics/collectors/hook-collector.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
/**
* Hook Collector — Verifies SYNAPSE hook registration and file integrity.
*
* NOTE: The SYNAPSE UserPromptSubmit hook is DEPRECATED. The skills-first
* architecture (CLAUDE.md + agent system prompts + .claude/rules/) provides
* equivalent context injection natively. The hook check now reports INFO
* instead of FAIL when the hook is not registered.
*
* Checks:
* - settings.local.json has UserPromptSubmit hook entry
* - settings.local.json has UserPromptSubmit hook entry (deprecated, INFO only)
* - Hook file exists at expected path
* - Hook file is valid Node.js (can be required)
*
* @module core/synapse/diagnostics/collectors/hook-collector
* @version 1.0.0
* @version 1.1.0
* @created Story SYN-13
*/

Expand All @@ -25,7 +30,7 @@ const path = require('path');
function collectHookStatus(projectRoot) {
const checks = [];

// Check 1: settings.local.json has hook entry
// Check 1: settings.local.json has hook entry (DEPRECATED — INFO only)
const settingsPath = path.join(projectRoot, '.claude', 'settings.local.json');
let hasHookRegistered = false;

Expand All @@ -51,16 +56,16 @@ function collectHookStatus(projectRoot) {

checks.push({
name: 'Hook registered',
status: hasHookRegistered ? 'PASS' : 'FAIL',
status: hasHookRegistered ? 'PASS' : 'INFO',
detail: hasHookRegistered
? 'settings.local.json has UserPromptSubmit entry for synapse-engine'
: 'No synapse-engine hook found in settings.local.json',
: 'DEPRECATED — hook not registered (not required with skills-first architecture)',
});
} else {
checks.push({
name: 'Hook registered',
status: 'FAIL',
detail: 'settings.local.json not found',
status: 'INFO',
detail: 'DEPRECATED — hook not registered (not required with skills-first architecture)',
});
}
} catch (error) {
Expand Down
Loading
Loading