Skip to content
Open
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
1 change: 1 addition & 0 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ jobs:
docker build _external/clawdbot \
--build-arg OPENCLAW_EXTENSIONS=acpx \
--build-arg OPENCLAW_INSTALL_GH_CLI=1 \
--build-arg OPENCLAW_INSTALL_DOC_TOOLCHAIN=1 \
-t "$REPO:$TAG"
docker push "$REPO:$TAG"

Expand Down
31 changes: 31 additions & 0 deletions backend/routes/registry/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,13 @@ If nothing changed → no post.
- Auto-source from GitHub when idle — don't wait for humans to assign work.
- If tools unavailable → \`HEARTBEAT_OK\` immediately.
`,
defaultSkills: [
{ id: 'github', reason: 'PR/repo operations and source control context.' },
{ id: 'officecli', reason: 'Generate DOCX/XLSX/PPTX deliverables for stakeholders (PRDs, briefs, reports).' },
{ id: 'pandic-office', reason: 'Markdown → PDF for weekly digests and audit summaries.' },
{ id: 'markdown-converter', reason: 'Read user-attached PDFs/DOCX as markdown for input.' },
{ id: 'pdf', reason: 'PDF extract / merge / split when working with stakeholder docs.' },
],
},
{
id: 'backend-engineer',
Expand Down Expand Up @@ -1467,6 +1474,14 @@ If Branch A just completed a task with a PR: also post the API contract (endpoin
- If tools unavailable → \`HEARTBEAT_OK\` immediately.
- HEARTBEAT_OK is a return value, NOT a chat message. Never post it.
`,
defaultSkills: [
{ id: 'github', reason: 'PR/repo operations, issue context, source control.' },
{ id: 'tmux', reason: 'Session management for long-running coding tasks.' },
{ id: 'officecli', reason: 'Generate DOCX/XLSX deliverables (API specs, schemas as docs) when needed.' },
{ id: 'pandic-office', reason: 'Markdown → PDF for stack-trace analysis or design notes shared in chat.' },
{ id: 'markdown-converter', reason: 'Read user-attached PDFs/DOCX/XLSX/specs as markdown for input.' },
{ id: 'pdf', reason: 'PDF extract / read when working with attached vendor docs or specs.' },
],
},
{
id: 'frontend-engineer',
Expand Down Expand Up @@ -1699,6 +1714,14 @@ For any message asking about frontend components, UI status, implementation deci
- Skip sender "pixel" — that's you.
- If tools unavailable → \`HEARTBEAT_OK\` immediately.
`,
defaultSkills: [
{ id: 'github', reason: 'PR/repo operations, issue context, source control.' },
{ id: 'tmux', reason: 'Session management for long-running coding tasks.' },
{ id: 'officecli', reason: 'Generate UI spec / mockup-doc deliverables (DOCX/PPTX) when needed.' },
{ id: 'pandic-office', reason: 'Markdown → PDF for design notes / accessibility audits shared in chat.' },
{ id: 'markdown-converter', reason: 'Read user-attached PDFs/DOCX/specs as markdown for input.' },
{ id: 'pdf', reason: 'PDF extract / read when working with attached design assets or specs.' },
],
},
{
id: 'devops-engineer',
Expand Down Expand Up @@ -1924,6 +1947,14 @@ For any message asking about infrastructure status, deployment decisions, CI/CD
- Skip sender "ops" — that's you.
- If tools unavailable → \`HEARTBEAT_OK\` immediately.
`,
defaultSkills: [
{ id: 'github', reason: 'PR/repo operations, issue context, source control.' },
{ id: 'tmux', reason: 'Session management for long-running coding tasks.' },
{ id: 'officecli', reason: 'Generate runbook / incident-report deliverables (DOCX/PDF) when needed.' },
{ id: 'pandic-office', reason: 'Markdown → PDF for incident timelines and post-mortem reports shared in chat.' },
{ id: 'markdown-converter', reason: 'Read user-attached PDFs (vendor docs, runbooks, k8s configs) as markdown for input.' },
{ id: 'pdf', reason: 'PDF extract / read when working with vendor docs or k8s reference material.' },
],
},
{
id: 'claude-code-agent',
Expand Down
29 changes: 29 additions & 0 deletions backend/routes/registry/provision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const {
issueUserTokenForInstallation,
} = require('./tokens');
const { PRESET_DEFINITIONS } = require('./presets');
const { applyPresetDefaultSkills } = require('../../services/presetSkillsAutoImport');

const provisionRouter = express.Router();

Expand Down Expand Up @@ -283,6 +284,33 @@ provisionRouter.post('/pods/:podId/agents/:name/provision', auth, async (req: an
}
}

// ADR-013 Phase 1: auto-import the preset's defaultSkills as PodAssets so
// syncOpenClawSkills (called below) picks them up and writes their
// SKILL.md files to the agent's workspace on the gateway PVC. Resolution
// order: local bundle (commonly-bundled-skills/<id>/SKILL.md) → upstream
// catalog. Reuses the same upsertImportedSkillAsset path the manual
// /api/skills/import route uses; idempotent across reprovisions.
const explicitPresetIdForSkills = (configPayload as any)?.presetId || null;
const matchedPresetForSkills: any = PRESET_DEFINITIONS.find(
(p: any) => p.id === (explicitPresetIdForSkills || normalizedInstanceId),
);
let presetSkillsApplied = null;
if (matchedPresetForSkills?.defaultSkills?.length && podId) {
try {
presetSkillsApplied = await applyPresetDefaultSkills({
podId: String(podId),
preset: matchedPresetForSkills,
userId,
});
} catch (skillErr: unknown) {
console.warn(
'[provision] applyPresetDefaultSkills failed:',
(skillErr as Error).message,
);
presetSkillsApplied = { error: (skillErr as Error).message };
}
}

let runtimeStart = null;
try {
runtimeStart = await startAgentRuntime(runtimeType, normalizedInstanceId, { gateway });
Expand Down Expand Up @@ -387,6 +415,7 @@ provisionRouter.post('/pods/:podId/agents/:name/provision', auth, async (req: an
runtimeRestarted: runtimeRestart?.restarted || false,
runtimeRestartError: runtimeRestart?.reason || null,
skillsSynced,
presetSkillsApplied,
sharedIdentity: true,
agentUsername: agentUser.username,
});
Expand Down
24 changes: 24 additions & 0 deletions backend/routes/registry/reprovision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const {
issueUserTokenForInstallation,
} = require('./tokens');
const { PRESET_DEFINITIONS } = require('./presets');
const { applyPresetDefaultSkills } = require('../../services/presetSkillsAutoImport');

const reprovisionInstallation = async ({
installation,
Expand Down Expand Up @@ -167,6 +168,28 @@ const reprovisionInstallation = async ({
}
}

// ADR-013 Phase 1: auto-import the preset's defaultSkills as PodAssets so
// syncOpenClawSkills (called below) picks them up and writes their SKILL.md
// files to the agent's workspace on the gateway PVC. Reuses the same
// upsertImportedSkillAsset path the manual /api/skills/import route uses;
// idempotent across reprovisions.
let presetSkillsApplied = null;
if (matchedPreset?.defaultSkills?.length && podId) {
try {
presetSkillsApplied = await applyPresetDefaultSkills({
podId: String(podId),
preset: matchedPreset,
userId: installation.installedBy || null,
});
} catch (skillErr: unknown) {
console.warn(
'[reprovision] applyPresetDefaultSkills failed:',
(skillErr as Error).message,
);
presetSkillsApplied = { error: (skillErr as Error).message };
}
}

let runtimeStart = null;
try {
runtimeStart = await startAgentRuntime(runtimeType, normalizedInstanceId, { gateway });
Expand Down Expand Up @@ -264,6 +287,7 @@ const reprovisionInstallation = async ({
runtimeRestartError: runtimeRestart?.reason || null,
tokenRotated: Boolean(runtimeIssued.token),
skillsSynced,
presetSkillsApplied,
};
};

Expand Down
Loading
Loading