diff --git a/.claude/commands/idaw/add.md b/.claude/commands/idaw/add.md
index 78c14f5d..6434b7a4 100644
--- a/.claude/commands/idaw/add.md
+++ b/.claude/commands/idaw/add.md
@@ -54,11 +54,16 @@ When `--yes` or `-y`: Skip clarification questions, create task with inferred de
```javascript
const args = $ARGUMENTS;
-const autoYes = /(-y|--yes)/.test(args);
+const autoYes = /(-y|--yes)\b/.test(args);
const fromIssue = args.match(/--from-issue\s+([\w,-]+)/)?.[1];
const typeFlag = args.match(/--type\s+([\w-]+)/)?.[1];
const priorityFlag = args.match(/--priority\s+(\d)/)?.[1];
-const description = args.replace(/(-y|--yes|--from-issue\s+[\w,-]+|--type\s+[\w-]+|--priority\s+\d)/g, '').trim().replace(/^["']|["']$/g, '');
+
+// Extract description: content inside quotes (preferred), or fallback to stripping flags
+const quotedMatch = args.match(/(?:^|\s)["']([^"']+)["']/);
+const description = quotedMatch
+ ? quotedMatch[1].trim()
+ : args.replace(/(-y|--yes|--from-issue\s+[\w,-]+|--type\s+[\w-]+|--priority\s+\d)/g, '').trim();
```
### Phase 2: Route — Import or Manual
@@ -74,10 +79,19 @@ const description = args.replace(/(-y|--yes|--from-issue\s+[\w,-]+|--type\s+[\w-
```javascript
const issueIds = fromIssue.split(',');
-for (const issueId of issueIds) {
- // 1. Fetch issue data
+// Fetch all issues once (outside loop)
+let issues = [];
+try {
const issueJson = Bash(`ccw issue list --json`);
- const issues = JSON.parse(issueJson).issues;
+ issues = JSON.parse(issueJson).issues || [];
+} catch (e) {
+ console.log(`Error fetching CCW issues: ${e.message || e}`);
+ console.log('Ensure ccw is installed and issues exist. Use /issue:new to create issues first.');
+ return;
+}
+
+for (const issueId of issueIds) {
+ // 1. Find issue data
const issue = issues.find(i => i.id === issueId.trim());
if (!issue) {
console.log(`Warning: Issue ${issueId} not found, skipping`);
diff --git a/.claude/commands/idaw/resume.md b/.claude/commands/idaw/resume.md
index 371b3518..da242139 100644
--- a/.claude/commands/idaw/resume.md
+++ b/.claude/commands/idaw/resume.md
@@ -366,8 +366,13 @@ function assembleSkillArgs(skillName, task, previousResult, autoYes, isFirst) {
let args = '';
if (isFirst) {
- const goal = `${task.title}\n${task.description}`;
- args = `"${goal.replace(/"/g, '\\"')}"`;
+ // Sanitize for shell safety
+ const goal = `${task.title}\n${task.description}`
+ .replace(/\\/g, '\\\\')
+ .replace(/"/g, '\\"')
+ .replace(/\$/g, '\\$')
+ .replace(/`/g, '\\`');
+ args = `"${goal}"`;
if (task.task_type === 'bugfix-hotfix') args += ' --hotfix';
} else if (previousResult?.session_id) {
args = `--session="${previousResult.session_id}"`;
diff --git a/.claude/commands/idaw/run.md b/.claude/commands/idaw/run.md
index c641b554..944e93fe 100644
--- a/.claude/commands/idaw/run.md
+++ b/.claude/commands/idaw/run.md
@@ -405,9 +405,13 @@ function assembleSkillArgs(skillName, task, previousResult, autoYes, isFirst) {
let args = '';
if (isFirst) {
- // First skill: pass task goal
- const goal = `${task.title}\n${task.description}`;
- args = `"${goal.replace(/"/g, '\\"')}"`;
+ // First skill: pass task goal — sanitize for shell safety
+ const goal = `${task.title}\n${task.description}`
+ .replace(/\\/g, '\\\\')
+ .replace(/"/g, '\\"')
+ .replace(/\$/g, '\\$')
+ .replace(/`/g, '\\`');
+ args = `"${goal}"`;
// bugfix-hotfix: add --hotfix
if (task.task_type === 'bugfix-hotfix') {
diff --git a/docs/public/icon-concepts.html b/docs/public/icon-concepts.html
index d7c685b1..1bcfe8bf 100644
--- a/docs/public/icon-concepts.html
+++ b/docs/public/icon-concepts.html
@@ -2802,14 +2802,14 @@