@web42/cli 0.1.3 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,7 @@ import chalk from "chalk";
5
5
  import inquirer from "inquirer";
6
6
  import { requireAuth } from "../utils/config.js";
7
7
  import { parseSkillMd } from "../utils/skill.js";
8
+ import { listBundledSkills, copySkillToWorkspace } from "../utils/bundled-skills.js";
8
9
  import { resolvePlatform, listPlatforms } from "../platforms/registry.js";
9
10
  import { AGENTS_MD, IDENTITY_MD, SOUL_MD, TOOLS_MD, USER_MD, HEARTBEAT_MD, INIT_BOOTSTRAP_MD, } from "../platforms/openclaw/templates.js";
10
11
  function detectWorkspaceSkills(cwd) {
@@ -20,7 +21,9 @@ function detectWorkspaceSkills(cwd) {
20
21
  if (existsSync(skillMd)) {
21
22
  const content = readFileSync(skillMd, "utf-8");
22
23
  const parsed = parseSkillMd(content, entry.name);
23
- skills.push(parsed);
24
+ if (!parsed.internal) {
25
+ skills.push({ name: parsed.name, description: parsed.description });
26
+ }
24
27
  }
25
28
  }
26
29
  }
@@ -32,7 +35,8 @@ function detectWorkspaceSkills(cwd) {
32
35
  }
33
36
  export const initCommand = new Command("init")
34
37
  .description("Create a manifest.json for your agent package")
35
- .action(async () => {
38
+ .option("--with-skills [names...]", "Add bundled starter skills (omit names to install all)")
39
+ .action(async (opts) => {
36
40
  const config = requireAuth();
37
41
  const cwd = process.cwd();
38
42
  const manifestPath = join(cwd, "manifest.json");
@@ -143,6 +147,48 @@ export const initCommand = new Command("init")
143
147
  if (skipped.length > 0) {
144
148
  console.log(chalk.dim(` Skipped (already exist): ${skipped.join(", ")}`));
145
149
  }
150
+ // Offer bundled starter skills
151
+ const bundled = listBundledSkills();
152
+ if (bundled.length > 0) {
153
+ let skillsToInstall = [];
154
+ if (opts.withSkills === true) {
155
+ skillsToInstall = bundled.map((s) => s.name);
156
+ }
157
+ else if (Array.isArray(opts.withSkills) && opts.withSkills.length > 0) {
158
+ skillsToInstall = opts.withSkills.filter((name) => bundled.some((s) => s.name === name));
159
+ const unknown = opts.withSkills.filter((name) => !bundled.some((s) => s.name === name));
160
+ if (unknown.length > 0) {
161
+ console.log(chalk.yellow(` Unknown skill(s): ${unknown.join(", ")}`));
162
+ }
163
+ }
164
+ else if (!opts.withSkills) {
165
+ console.log();
166
+ const { selectedSkills } = await inquirer.prompt([
167
+ {
168
+ type: "checkbox",
169
+ name: "selectedSkills",
170
+ message: "Add starter skills to your workspace?",
171
+ choices: bundled.map((s) => ({
172
+ name: `${s.name} — ${s.description}`,
173
+ value: s.name,
174
+ checked: false,
175
+ })),
176
+ },
177
+ ]);
178
+ skillsToInstall = selectedSkills;
179
+ }
180
+ if (skillsToInstall.length > 0) {
181
+ const installed = [];
182
+ for (const name of skillsToInstall) {
183
+ if (copySkillToWorkspace(name, cwd)) {
184
+ installed.push(name);
185
+ }
186
+ }
187
+ if (installed.length > 0) {
188
+ console.log(chalk.green(` Added starter skill(s): ${installed.join(", ")}`));
189
+ }
190
+ }
191
+ }
146
192
  console.log();
147
193
  console.log(chalk.dim("Run `web42 pack` to bundle your agent, or `web42 push` to pack and publish."));
148
194
  });
@@ -24,15 +24,24 @@ export const packCommand = new Command("pack")
24
24
  const spinner = ora("Packing agent...").start();
25
25
  try {
26
26
  const result = await openclawAdapter.pack({ cwd, outputDir: opts.output });
27
- // Detect skills from packed files (skills/*/SKILL.md pattern)
27
+ // Detect skills from packed files and strip internal ones
28
+ const internalSkillPrefixes = [];
28
29
  const detectedSkills = [];
29
30
  for (const f of result.files) {
30
31
  const match = f.path.match(/^skills\/([^/]+)\/SKILL\.md$/);
31
32
  if (match) {
32
33
  const parsed = parseSkillMd(f.content, match[1]);
33
- detectedSkills.push(parsed);
34
+ if (parsed.internal) {
35
+ internalSkillPrefixes.push(`skills/${match[1]}/`);
36
+ }
37
+ else {
38
+ detectedSkills.push({ name: parsed.name, description: parsed.description });
39
+ }
34
40
  }
35
41
  }
42
+ if (internalSkillPrefixes.length > 0) {
43
+ result.files = result.files.filter((f) => !internalSkillPrefixes.some((prefix) => f.path.startsWith(prefix)));
44
+ }
36
45
  if (detectedSkills.length > 0) {
37
46
  manifest.skills = detectedSkills.sort((a, b) => a.name.localeCompare(b.name));
38
47
  }
@@ -7,6 +7,7 @@ import ora from "ora";
7
7
  import { apiPost } from "../utils/api.js";
8
8
  import { requireAuth } from "../utils/config.js";
9
9
  import { openclawAdapter } from "../platforms/openclaw/adapter.js";
10
+ import { parseSkillMd } from "../utils/skill.js";
10
11
  function hashContent(content) {
11
12
  return createHash("sha256").update(content).digest("hex");
12
13
  }
@@ -68,6 +69,18 @@ export const pushCommand = new Command("push")
68
69
  else {
69
70
  spinner.text = "No .web42/ found, packing automatically...";
70
71
  const result = await openclawAdapter.pack({ cwd, outputDir: ".web42" });
72
+ const internalPrefixes = [];
73
+ for (const f of result.files) {
74
+ const skillMatch = f.path.match(/^skills\/([^/]+)\/SKILL\.md$/);
75
+ if (skillMatch) {
76
+ const parsed = parseSkillMd(f.content, skillMatch[1]);
77
+ if (parsed.internal)
78
+ internalPrefixes.push(`skills/${skillMatch[1]}/`);
79
+ }
80
+ }
81
+ if (internalPrefixes.length > 0) {
82
+ result.files = result.files.filter((f) => !internalPrefixes.some((p) => f.path.startsWith(p)));
83
+ }
71
84
  processedFiles = result.files;
72
85
  const existingKeys = new Set((manifest.configVariables ?? []).map((v) => v.key));
73
86
  for (const cv of result.configVariables) {
@@ -78,7 +91,6 @@ export const pushCommand = new Command("push")
78
91
  existingKeys.add(cv.key);
79
92
  }
80
93
  }
81
- // Write the packed artifact so it can be inspected later
82
94
  mkdirSync(web42Dir, { recursive: true });
83
95
  for (const file of result.files) {
84
96
  const filePath = join(web42Dir, file.path);
@@ -0,0 +1,9 @@
1
+ export interface EmbeddedFile {
2
+ path: string;
3
+ content: string;
4
+ }
5
+ export interface EmbeddedSkill {
6
+ name: string;
7
+ files: EmbeddedFile[];
8
+ }
9
+ export declare const EMBEDDED_SKILLS: EmbeddedSkill[];
@@ -0,0 +1,28 @@
1
+ // AUTO-GENERATED by scripts/embed-skills.ts — do not edit manually
2
+ export const EMBEDDED_SKILLS = [
3
+ {
4
+ name: "web42-publish-prep",
5
+ files: [
6
+ {
7
+ path: "_meta.json",
8
+ content: "{\n \"name\": \"web42-publish-prep\",\n \"tagline\": \"Prepare your agent for the Web42 marketplace\",\n \"description\": \"Guides agents through the full publish lifecycle: init, manifest enrichment, README writing, file auditing, and validation before pushing to the Web42 marketplace.\",\n \"category\": \"development\",\n \"tags\": [\"web42\", \"marketplace\", \"publishing\", \"cli\", \"agent-packaging\"],\n \"version\": \"1.0.0\",\n \"license\": \"MIT\",\n \"pricing\": \"free\",\n \"support_url\": \"https://github.com/web42-ai/web42-marketplace/issues\",\n \"homepage\": \"https://web42.ai/docs/publishing\",\n \"requiredConfigPaths\": [],\n \"primaryCredential\": null,\n \"requires\": {\n \"anyBins\": [\"web42\"]\n }\n}\n",
9
+ },
10
+ {
11
+ path: "assets/readme-template.md",
12
+ content: "# {Agent Name}\n\n<!-- \n This is a starting point, not a form. Rewrite it, restructure it, make it yours.\n The marketplace renders full Markdown — use it. GIFs, videos, screenshots, emoji, whatever tells your story.\n-->\n\n{A bold opening line. What changes for the user when they have you? Don't describe yourself — describe the outcome.}\n\n<!-- Optional: embed a GIF or demo video here -->\n<!-- ![Demo](https://your-demo-url.gif) -->\n\n---\n\n## What I Do\n\n{2–3 sentences, max. What's your superpower? Write this like you're explaining to a friend, not a spec sheet.}\n\n## Try Me\n\n{3–5 concrete scenarios. Not features — experiences. Make the reader feel what it's like to work with you.}\n\n- **\"Draft my weekly standup notes from yesterday's git commits and Slack threads.\"**\n- **\"Summarize this 40-page PDF into a one-page brief I can send to my team.\"**\n- **\"Monitor my inbox and ping me only when something actually matters.\"**\n\n<!-- Replace these with real scenarios that match what you actually do. -->\n\n## Quickstart\n\n```bash\nweb42 openclaw install @{author}/{name}\n```\n\n{One sentence on what happens after install. Does the agent need a restart? A quick config? A first conversation?}\n\n## Configuration\n\n{List any API keys, tokens, or setup the user needs to provide. Be specific about where to find each one.}\n\n| Variable | What It Is | Where to Get It |\n|----------|-----------|-----------------|\n| `EXAMPLE_API_KEY` | Access token for Example API | [Example Dashboard → Settings → API](https://example.com/settings) |\n\n<!-- Remove this section entirely if the agent needs no configuration. -->\n\n---\n\n<!-- \n Optional sections you might add:\n - \"How I Work\" (high-level, no secrets — just enough to build trust)\n - \"Limitations\" (honesty builds credibility)\n - \"Changelog\" (what's new in this version)\n - \"Credits\" (shoutouts, inspirations)\n \n Or make up your own sections. There are no rules here.\n-->\n",
13
+ },
14
+ {
15
+ path: "references/file-hygiene.md",
16
+ content: "# File Hygiene Checklist\n\nBefore packing, audit the workspace for files that should not ship to buyers. The CLI's pack command automatically excludes some patterns, but manual review catches everything else.\n\n## Automatically Excluded by the CLI\n\nThese patterns are hardcoded in the pack command and will never appear in the `.web42/` artifact:\n\n| Pattern | Reason |\n|---------|--------|\n| `auth-profiles.json` | Platform authentication credentials |\n| `MEMORY.md` | Creator's long-term memory — personal context |\n| `memory/**` | Daily memory logs — personal context |\n| `sessions/**` | Session history — personal context |\n| `.git/**` | Version control internals |\n| `node_modules/**` | Dependencies (not portable) |\n| `.DS_Store` | macOS filesystem metadata |\n| `*.log` | Log files |\n| `openclaw.json` | Platform config (contains agent bindings, channel secrets) |\n| `.openclaw/credentials/**` | Platform credentials |\n| `.web42/**` | Previous pack artifacts |\n| `.web42ignore` | Pack ignore config (meta, not content) |\n| `manifest.json` | Shipped separately as structured data |\n| `USER.md` | Always rewritten with a blank template on install |\n\n## Files to Flag for Manual Review\n\nThese are NOT auto-excluded but often contain content that should not ship:\n\n### Personal Data\n\n- **`HEARTBEAT.md`** — If it contains creator-specific tasks, reminders, or routines. Reset to the scaffold default (empty with comments) unless the tasks are part of the agent's intended behavior.\n- **`SOUL.md`** — If it references the creator by name, contains personal preferences, or has inside jokes. Generalize to describe the agent's intended persona, not the creator's personality.\n- **`IDENTITY.md`** — If it contains the creator's chosen name/emoji/avatar. The buyer's agent should form its own identity. Reset to the scaffold template or write a persona description that fits the agent's purpose.\n- **`TOOLS.md`** — If it contains the creator's SSH hosts, camera names, device nicknames, etc. Reset to the scaffold template with example placeholders.\n\n### Secrets and Credentials\n\n- **`.env` / `.env.local`** — Should never be in the workspace root. If present, flag immediately.\n- **`.web42.config.json`** — Contains config variable values from the creator's install. Must not ship.\n- **Hardcoded API keys in skill files** — The CLI strips known patterns (`sk-...`, `ghp_...`, bearer tokens), but custom keys may slip through. Grep for suspicious patterns: long hex/base64 strings, `token`, `secret`, `password`, `apikey`.\n\n### Development Artifacts\n\n- **`.vscode/` / `.cursor/` / `.idea/`** — IDE configuration. Not relevant to buyers.\n- **`__pycache__/` / `*.pyc`** — Python bytecode.\n- **`Thumbs.db`** — Windows thumbnail cache.\n- **`*.bak` / `*.swp` / `*.tmp`** — Editor backup/swap files.\n- **`test/` / `tests/` / `__tests__/`** — Test files, unless they are part of the agent's functionality.\n- **Build outputs** — `dist/`, `build/`, `out/` directories.\n\n### Large or Binary Files\n\n- The pack command skips files larger than 1 MB.\n- Binary files (images, compiled executables) are skipped automatically (UTF-8 decode failure).\n- If the agent needs images (e.g., for the README cover), use `coverImage` in the manifest or host them externally.\n\n## Using `.web42ignore`\n\nCreate a `.web42ignore` file in the workspace root to exclude additional patterns. Syntax follows `.gitignore`:\n\n```\n# Exclude test fixtures\ntests/**\nfixtures/**\n\n# Exclude draft documents\ndrafts/**\n\n# Exclude local scripts not part of the agent\nscripts/local-*.sh\n```\n\nThe `.web42ignore` file itself is automatically excluded from the artifact.\n\n## Verification\n\nAfter auditing, always run:\n\n```\nweb42 pack --dry-run\n```\n\nThis prints every file that would be included. Review the list for:\n\n1. **Unexpected files** — anything you don't recognize or didn't intend to ship\n2. **File count** — a typical agent has 5–30 files. Hundreds of files suggests something is wrong.\n3. **Sensitive content** — spot-check a few files for leaked secrets or personal data\n",
17
+ },
18
+ {
19
+ path: "references/manifest-fields.md",
20
+ content: "# manifest.json Field Reference\n\nThe manifest describes your agent package. Format version is always `\"agentpkg/1\"`.\n\n## Required Fields\n\n### `name` (string)\n\nThe package identifier. Appears in install commands and URLs.\n\n- **Constraints:** 1–100 characters. Lowercase alphanumeric with hyphens only. Must start with a letter or number. Regex: `^[a-z0-9][a-z0-9-]*$`\n- **Good:** `support-bot`, `code-reviewer`, `daily-digest`\n- **Bad:** `My_Agent`, `Support Bot`, `-agent`\n- **Guidance:** Pick something short, memorable, and descriptive of what the agent does. This becomes the slug in `@author/name`.\n\n### `description` (string)\n\nA short pitch for the agent. Shown in search results and the marketplace listing.\n\n- **Constraints:** 1–500 characters.\n- **Good:** \"Drafts weekly team reports from your CRM data and posts them to Slack every Monday.\"\n- **Bad:** \"An AI agent.\" / \"This agent uses GPT-4 to process natural language queries against a database.\"\n- **Guidance:** Lead with the benefit to the user. What problem disappears? Avoid technical jargon about how it works internally.\n\n### `version` (string)\n\nSemantic version of the package.\n\n- **Constraints:** Must match `MAJOR.MINOR.PATCH` (e.g., `1.0.0`).\n- **Guidance:** Start at `1.0.0` for first publish. Bump `PATCH` for fixes, `MINOR` for new capabilities, `MAJOR` for breaking changes to config or behavior.\n\n### `author` (string)\n\nYour Web42 username. Set automatically by `web42 init` from your auth credentials.\n\n- **Constraints:** Non-empty string.\n- **Guidance:** Don't edit manually — it's populated from `web42 auth whoami`.\n\n## Optional Fields\n\n### `platform` (string)\n\nTarget agent platform.\n\n- **Values:** Currently only `\"openclaw\"`.\n- **Guidance:** Set during `web42 init` based on the platform prompt.\n\n### `skills` (array)\n\nList of skills the agent provides. Each entry has `name` (string) and `description` (string).\n\n- **Auto-detected** from `skills/*/SKILL.md` during init and pack.\n- **Guidance:** Don't edit manually. Add skills by creating `skills/<name>/SKILL.md` in your workspace. Internal skills (with `internal: true` in frontmatter) are automatically excluded.\n\n### `plugins` (string array)\n\nReserved for future use.\n\n- **Default:** `[]`\n- **Guidance:** Leave empty for now.\n\n### `modelPreferences` (object)\n\nPreferred LLM models for this agent.\n\n- **Fields:** `primary` (string, optional), `fallback` (string, optional)\n- **Example:** `{ \"primary\": \"claude-sonnet-4-20250514\" }`\n- **Guidance:** Set `primary` to the model the agent is designed and tested for. The `fallback` is used if the primary is unavailable. During install, the CLI will prompt buyers for the corresponding provider API key.\n\n### `tags` (string array)\n\nSearchable labels for marketplace discoverability.\n\n- **Default:** `[]`\n- **Good:** `[\"support\", \"crm\", \"slack\", \"weekly-reports\"]`\n- **Bad:** `[\"ai\", \"agent\", \"good\"]` (too generic)\n- **Guidance:** 3–6 tags. Think about what a buyer would search for. Mix category terms (\"support\", \"finance\") with capability terms (\"slack-integration\", \"pdf-generation\").\n\n### `coverImage` (string)\n\nPath to a cover image file, relative to workspace root.\n\n- **Guidance:** Optional but recommended. A good cover image dramatically improves click-through on the marketplace. Use a 1200x630 or 1200x1200 image.\n\n### `demoVideoUrl` (string)\n\nURL to a demo video.\n\n- **Constraints:** Must be a valid URL.\n- **Guidance:** A 1–3 minute video showing the agent in action converts far better than text alone. Host on YouTube, Loom, or similar.\n\n### `configVariables` (array)\n\nSecrets and configuration values that buyers provide during install.\n\n- **Each entry:** `{ key, label, description?, required, default? }`\n - `key` — Environment variable name (e.g., `SLACK_BOT_TOKEN`)\n - `label` — Human-readable name shown in the install prompt (e.g., \"Slack Bot Token\")\n - `description` — Optional help text explaining where to find this value\n - `required` — Whether install should block without it\n - `default` — Optional default value\n- **Auto-detected** from skill files during pack (secrets are stripped and replaced with placeholders).\n- **Guidance:** For each config variable, make the `label` and `description` crystal clear. A buyer who has never seen your agent should understand exactly what to provide and where to get it.\n\n## Example Manifest\n\n```json\n{\n \"format\": \"agentpkg/1\",\n \"platform\": \"openclaw\",\n \"name\": \"weekly-digest\",\n \"description\": \"Summarizes your team's CRM activity and posts a digest to Slack every Monday morning.\",\n \"version\": \"1.0.0\",\n \"author\": \"alice\",\n \"skills\": [\n { \"name\": \"crm-reader\", \"description\": \"Query CRM data for weekly activity\" },\n { \"name\": \"slack-poster\", \"description\": \"Post formatted messages to Slack channels\" }\n ],\n \"plugins\": [],\n \"modelPreferences\": { \"primary\": \"claude-sonnet-4-20250514\" },\n \"tags\": [\"crm\", \"slack\", \"weekly-reports\", \"productivity\"],\n \"coverImage\": \"assets/cover.png\",\n \"demoVideoUrl\": \"https://www.youtube.com/watch?v=example\",\n \"configVariables\": [\n {\n \"key\": \"CRM_API_KEY\",\n \"label\": \"CRM API Key\",\n \"description\": \"Found in your CRM dashboard under Settings > API\",\n \"required\": true\n },\n {\n \"key\": \"SLACK_BOT_TOKEN\",\n \"label\": \"Slack Bot Token\",\n \"description\": \"Create a Slack app at api.slack.com and copy the Bot User OAuth Token\",\n \"required\": true\n }\n ]\n}\n```\n",
21
+ },
22
+ {
23
+ path: "SKILL.md",
24
+ content: "---\nname: web42-publish-prep\ndescription: \"This skill should be used when the user asks to 'prepare my agent for Web42', 'publish to Web42', 'set up web42 CLI', 'create a manifest', 'write an agent README', 'clean up files before pushing', 'init web42', or needs help packaging an agent project for the Web42 marketplace. Guides the full lifecycle from init through push-ready state.\"\ninternal: true\nmetadata:\n clawdbot:\n emoji: \"📦\"\n requires:\n anyBins: [\"web42\"]\n os: [\"linux\", \"darwin\", \"win32\"]\n---\n\n# Web42 Publish Prep\n\nPrepare an agent project for publishing to the Web42 marketplace. This skill covers the full lifecycle: initializing the project, populating the manifest, writing a compelling README, and auditing workspace files so only the right content ships to users.\n\n## When to Activate\n\nActivate when the user wants to get their agent ready for the Web42 marketplace — whether starting from scratch or cleaning up an existing project before push.\n\n## Prerequisites\n\n- The Web42 CLI must be installed (`npx web42-cli` or globally via `npm i -g web42-cli`).\n- The user must be authenticated (`web42 auth login`). Verify with `web42 auth whoami`.\n- The workspace must contain a supported platform config (currently OpenClaw — `openclaw.json`).\n\nIf any prerequisite is missing, guide the user through resolving it before proceeding.\n\n## Workflow\n\n### Phase 1 — Initialize the Project\n\nCheck whether `manifest.json` already exists in the workspace root.\n\n- **If missing:** Run `web42 init` interactively. The CLI prompts for platform, description, version, and detects skills from `skills/*/SKILL.md`.\n- **If present:** Read and validate the existing manifest against the field reference in `references/manifest-fields.md`. Report any missing or invalid fields.\n\nAfter init, verify that the scaffolded platform files exist (`AGENTS.md`, `IDENTITY.md`, `SOUL.md`, `TOOLS.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `USER.md`). If the user already customized these, do not overwrite — just confirm they are present.\n\n### Phase 2 — Enrich the Manifest\n\nRead the current `manifest.json` and walk through each field with the user. Consult `references/manifest-fields.md` for the full field reference.\n\nKey actions:\n\n1. **`name`** — Confirm it is lowercase-hyphenated and reflects the agent's purpose. Suggest alternatives if generic.\n2. **`description`** — Must be 1–500 characters. Draft a concise, benefit-oriented description that tells a potential buyer what the agent *does for them*.\n3. **`version`** — Ensure semver format (`MAJOR.MINOR.PATCH`).\n4. **`tags`** — Suggest 3–6 relevant tags for discoverability.\n5. **`skills`** — Auto-detected from `skills/*/SKILL.md`. If none found, ask if skills should be documented.\n6. **`configVariables`** — For each detected secret/config, ensure `label` and `description` are clear enough for a buyer.\n7. **`modelPreferences`** — Set `primary` to the intended model. Optionally set a `fallback`.\n8. **`coverImage`** — Ask if the user has a cover image (path relative to workspace).\n9. **`demoVideoUrl`** — Ask if there is a demo video URL to include.\n\nWrite the updated `manifest.json` only after user confirmation.\n\n### Phase 3 — Write the README\n\nThe README is the storefront — the agent's pitch deck. Read `assets/readme-template.md` for inspiration, then write a README that lets the agent's personality shine.\n\nPrinciples:\n\n- **Lead with outcomes, not internals.** Paint the picture of life *with* this agent.\n- **Show personality.** Write in the agent's own voice — confident, creative, even playful.\n- **Use rich media.** GIFs, demo videos, screenshots, embedded links. The marketplace renders full Markdown.\n- **Give concrete scenarios.** \"Ask me to...\" or \"Imagine you need to...\" — make it visceral.\n- **Include practical info** (install command, required config) but don't let it dominate.\n- **Don't reveal the recipe.** Focus on outcomes, not system prompts or internal file structures.\n\nWrite to `README.md` at workspace root. If one already exists, show a diff and ask before overwriting.\n\n### Phase 4 — Audit Workspace Files\n\nBefore packing, scan the workspace for files that should not ship to buyers. Consult `references/file-hygiene.md` for the full checklist.\n\nCommon issues to flag:\n\n- **Personal data:** `USER.md`, `MEMORY.md`, `memory/` directory, `HEARTBEAT.md` with creator-specific tasks\n- **Secrets:** `.env`, `.env.local`, API keys hardcoded in files, `.web42.config.json`\n- **Development artifacts:** `node_modules/`, `.git/`, IDE configs, build outputs\n- **Platform junk:** `.DS_Store`, `Thumbs.db`, `__pycache__/`\n- **Overly personal SOUL.md or IDENTITY.md:** Suggest generalizing if they reference the creator rather than the agent persona\n\nFor each flagged item:\n\n1. Explain why it might be a problem.\n2. Ask the user whether to remove, reset to scaffold default, or keep it.\n3. If unsure, recommend `web42 pack --dry-run` to preview the bundle.\n\n### Phase 5 — Validate and Preview\n\nRun `web42 pack --dry-run` to show exactly what files will be included. Review together:\n\n- Confirm file count and total size are reasonable.\n- Verify no secrets leaked (the CLI strips known patterns, but manual review catches edge cases).\n- Ensure `README.md` is present (push reads it from workspace root).\n\nWhen clean, inform the user they can publish with `web42 push`. The agent is created **private** by default — remind them to toggle visibility on the marketplace when ready.\n\n## CLI Quick Reference\n\n| Command | Purpose |\n|---------|---------|\n| `web42 auth login` | Authenticate via GitHub OAuth |\n| `web42 auth whoami` | Check current auth status |\n| `web42 init` | Scaffold `manifest.json` + platform files |\n| `web42 pack --dry-run` | Preview packaged files without writing |\n| `web42 pack` | Bundle into `.web42/` directory |\n| `web42 push` | Pack (if needed) and upload to marketplace |\n| `web42 pull` | Fetch latest published files back locally |\n\n## Resources\n\n### References\n- **`references/manifest-fields.md`** — Complete manifest.json field reference with types, constraints, and guidance.\n- **`references/file-hygiene.md`** — Checklist of files and patterns to audit before packing.\n\n### Assets\n- **`assets/readme-template.md`** — Inspirational README template for the marketplace storefront.\n",
25
+ },
26
+ ],
27
+ },
28
+ ];
@@ -0,0 +1,6 @@
1
+ export interface BundledSkill {
2
+ name: string;
3
+ description: string;
4
+ }
5
+ export declare function listBundledSkills(): BundledSkill[];
6
+ export declare function copySkillToWorkspace(skillName: string, cwd: string): boolean;
@@ -0,0 +1,29 @@
1
+ import { writeFileSync, mkdirSync } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { parseSkillMd } from "./skill.js";
4
+ import { EMBEDDED_SKILLS } from "../generated/embedded-skills.js";
5
+ export function listBundledSkills() {
6
+ const skills = [];
7
+ for (const skill of EMBEDDED_SKILLS) {
8
+ const skillMdFile = skill.files.find((f) => f.path === "SKILL.md");
9
+ if (!skillMdFile)
10
+ continue;
11
+ const parsed = parseSkillMd(skillMdFile.content, skill.name);
12
+ skills.push({ name: parsed.name, description: parsed.description });
13
+ }
14
+ return skills.sort((a, b) => a.name.localeCompare(b.name));
15
+ }
16
+ export function copySkillToWorkspace(skillName, cwd) {
17
+ const skill = EMBEDDED_SKILLS.find((s) => s.name === skillName);
18
+ if (!skill)
19
+ return false;
20
+ const targetDir = join(cwd, "skills", skillName);
21
+ for (const file of skill.files) {
22
+ if (file.path === "_meta.json")
23
+ continue;
24
+ const filePath = join(targetDir, file.path);
25
+ mkdirSync(dirname(filePath), { recursive: true });
26
+ writeFileSync(filePath, file.content, "utf-8");
27
+ }
28
+ return true;
29
+ }
@@ -1,4 +1,6 @@
1
- export declare function parseSkillMd(content: string, fallbackName: string): {
1
+ export interface ParsedSkill {
2
2
  name: string;
3
3
  description: string;
4
- };
4
+ internal: boolean;
5
+ }
6
+ export declare function parseSkillMd(content: string, fallbackName: string): ParsedSkill;
@@ -1,12 +1,31 @@
1
+ function parseFrontmatter(lines) {
2
+ const frontmatter = {};
3
+ if (lines[0]?.trim() !== "---")
4
+ return { frontmatter, bodyStartIndex: 0 };
5
+ let i = 1;
6
+ for (; i < lines.length; i++) {
7
+ if (lines[i].trim() === "---")
8
+ return { frontmatter, bodyStartIndex: i + 1 };
9
+ const match = lines[i].match(/^(\w+)\s*:\s*(.*)$/);
10
+ if (match) {
11
+ const val = match[2].trim().replace(/^["']|["']$/g, "");
12
+ frontmatter[match[1]] = val;
13
+ }
14
+ }
15
+ return { frontmatter, bodyStartIndex: 0 };
16
+ }
1
17
  export function parseSkillMd(content, fallbackName) {
2
18
  const lines = content.split("\n");
3
- let name = fallbackName;
19
+ const { frontmatter, bodyStartIndex } = parseFrontmatter(lines);
20
+ let name = frontmatter.name || fallbackName;
21
+ const internal = frontmatter.internal === "true";
4
22
  const descriptionLines = [];
5
- let i = 0;
23
+ let i = bodyStartIndex;
6
24
  for (; i < lines.length; i++) {
7
25
  const headingMatch = lines[i].match(/^#\s+(.+)/);
8
26
  if (headingMatch) {
9
- name = headingMatch[1].trim();
27
+ if (!frontmatter.name)
28
+ name = headingMatch[1].trim();
10
29
  i++;
11
30
  break;
12
31
  }
@@ -16,6 +35,8 @@ export function parseSkillMd(content, fallbackName) {
16
35
  break;
17
36
  descriptionLines.push(lines[i]);
18
37
  }
19
- const description = descriptionLines.join("\n").trim();
20
- return { name, description: description || `Skill: ${fallbackName}` };
38
+ const description = frontmatter.description ||
39
+ descriptionLines.join("\n").trim() ||
40
+ `Skill: ${fallbackName}`;
41
+ return { name, description, internal };
21
42
  }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const CLI_VERSION = "0.1.3";
1
+ export declare const CLI_VERSION = "0.1.6";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const CLI_VERSION = "0.1.3";
1
+ export const CLI_VERSION = "0.1.6";
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@web42/cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "description": "CLI for the Web42 Agent Marketplace - push, install, and remix OpenClaw agent packages",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "web42": "./dist/index.js"
8
8
  },
9
9
  "scripts": {
10
- "build": "tsc",
11
- "build:binary": "bash scripts/sync-version.sh && bash scripts/build-binaries.sh",
10
+ "embed-skills": "bun scripts/embed-skills.ts",
11
+ "build": "npm run embed-skills && tsc",
12
+ "build:binary": "bash scripts/sync-version.sh && npm run embed-skills && bash scripts/build-binaries.sh",
12
13
  "dev": "tsc --watch",
13
14
  "start": "node dist/index.js"
14
15
  },
@@ -32,7 +33,8 @@
32
33
  },
33
34
  "files": [
34
35
  "dist/**/*.js",
35
- "dist/**/*.d.ts"
36
+ "dist/**/*.d.ts",
37
+ "skills/**"
36
38
  ],
37
39
  "keywords": [
38
40
  "web42",
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: web42-publish-prep
3
+ description: "This skill should be used when the user asks to 'prepare my agent for Web42', 'publish to Web42', 'set up web42 CLI', 'create a manifest', 'write an agent README', 'clean up files before pushing', 'init web42', or needs help packaging an agent project for the Web42 marketplace. Guides the full lifecycle from init through push-ready state."
4
+ internal: true
5
+ metadata:
6
+ clawdbot:
7
+ emoji: "📦"
8
+ requires:
9
+ anyBins: ["web42"]
10
+ os: ["linux", "darwin", "win32"]
11
+ ---
12
+
13
+ # Web42 Publish Prep
14
+
15
+ Prepare an agent project for publishing to the Web42 marketplace. This skill covers the full lifecycle: initializing the project, populating the manifest, writing a compelling README, and auditing workspace files so only the right content ships to users.
16
+
17
+ ## When to Activate
18
+
19
+ Activate when the user wants to get their agent ready for the Web42 marketplace — whether starting from scratch or cleaning up an existing project before push.
20
+
21
+ ## Prerequisites
22
+
23
+ - The Web42 CLI must be installed (`npx web42-cli` or globally via `npm i -g web42-cli`).
24
+ - The user must be authenticated (`web42 auth login`). Verify with `web42 auth whoami`.
25
+ - The workspace must contain a supported platform config (currently OpenClaw — `openclaw.json`).
26
+
27
+ If any prerequisite is missing, guide the user through resolving it before proceeding.
28
+
29
+ ## Workflow
30
+
31
+ ### Phase 1 — Initialize the Project
32
+
33
+ Check whether `manifest.json` already exists in the workspace root.
34
+
35
+ - **If missing:** Run `web42 init` interactively. The CLI prompts for platform, description, version, and detects skills from `skills/*/SKILL.md`.
36
+ - **If present:** Read and validate the existing manifest against the field reference in `references/manifest-fields.md`. Report any missing or invalid fields.
37
+
38
+ After init, verify that the scaffolded platform files exist (`AGENTS.md`, `IDENTITY.md`, `SOUL.md`, `TOOLS.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `USER.md`). If the user already customized these, do not overwrite — just confirm they are present.
39
+
40
+ ### Phase 2 — Enrich the Manifest
41
+
42
+ Read the current `manifest.json` and walk through each field with the user. Consult `references/manifest-fields.md` for the full field reference.
43
+
44
+ Key actions:
45
+
46
+ 1. **`name`** — Confirm it is lowercase-hyphenated and reflects the agent's purpose. Suggest alternatives if generic.
47
+ 2. **`description`** — Must be 1–500 characters. Draft a concise, benefit-oriented description that tells a potential buyer what the agent *does for them*.
48
+ 3. **`version`** — Ensure semver format (`MAJOR.MINOR.PATCH`).
49
+ 4. **`tags`** — Suggest 3–6 relevant tags for discoverability.
50
+ 5. **`skills`** — Auto-detected from `skills/*/SKILL.md`. If none found, ask if skills should be documented.
51
+ 6. **`configVariables`** — For each detected secret/config, ensure `label` and `description` are clear enough for a buyer.
52
+ 7. **`modelPreferences`** — Set `primary` to the intended model. Optionally set a `fallback`.
53
+ 8. **`coverImage`** — Ask if the user has a cover image (path relative to workspace).
54
+ 9. **`demoVideoUrl`** — Ask if there is a demo video URL to include.
55
+
56
+ Write the updated `manifest.json` only after user confirmation.
57
+
58
+ ### Phase 3 — Write the README
59
+
60
+ The README is the storefront — the agent's pitch deck. Read `assets/readme-template.md` for inspiration, then write a README that lets the agent's personality shine.
61
+
62
+ Principles:
63
+
64
+ - **Lead with outcomes, not internals.** Paint the picture of life *with* this agent.
65
+ - **Show personality.** Write in the agent's own voice — confident, creative, even playful.
66
+ - **Use rich media.** GIFs, demo videos, screenshots, embedded links. The marketplace renders full Markdown.
67
+ - **Give concrete scenarios.** "Ask me to..." or "Imagine you need to..." — make it visceral.
68
+ - **Include practical info** (install command, required config) but don't let it dominate.
69
+ - **Don't reveal the recipe.** Focus on outcomes, not system prompts or internal file structures.
70
+
71
+ Write to `README.md` at workspace root. If one already exists, show a diff and ask before overwriting.
72
+
73
+ ### Phase 4 — Audit Workspace Files
74
+
75
+ Before packing, scan the workspace for files that should not ship to buyers. Consult `references/file-hygiene.md` for the full checklist.
76
+
77
+ Common issues to flag:
78
+
79
+ - **Personal data:** `USER.md`, `MEMORY.md`, `memory/` directory, `HEARTBEAT.md` with creator-specific tasks
80
+ - **Secrets:** `.env`, `.env.local`, API keys hardcoded in files, `.web42.config.json`
81
+ - **Development artifacts:** `node_modules/`, `.git/`, IDE configs, build outputs
82
+ - **Platform junk:** `.DS_Store`, `Thumbs.db`, `__pycache__/`
83
+ - **Overly personal SOUL.md or IDENTITY.md:** Suggest generalizing if they reference the creator rather than the agent persona
84
+
85
+ For each flagged item:
86
+
87
+ 1. Explain why it might be a problem.
88
+ 2. Ask the user whether to remove, reset to scaffold default, or keep it.
89
+ 3. If unsure, recommend `web42 pack --dry-run` to preview the bundle.
90
+
91
+ ### Phase 5 — Validate and Preview
92
+
93
+ Run `web42 pack --dry-run` to show exactly what files will be included. Review together:
94
+
95
+ - Confirm file count and total size are reasonable.
96
+ - Verify no secrets leaked (the CLI strips known patterns, but manual review catches edge cases).
97
+ - Ensure `README.md` is present (push reads it from workspace root).
98
+
99
+ When clean, inform the user they can publish with `web42 push`. The agent is created **private** by default — remind them to toggle visibility on the marketplace when ready.
100
+
101
+ ## CLI Quick Reference
102
+
103
+ | Command | Purpose |
104
+ |---------|---------|
105
+ | `web42 auth login` | Authenticate via GitHub OAuth |
106
+ | `web42 auth whoami` | Check current auth status |
107
+ | `web42 init` | Scaffold `manifest.json` + platform files |
108
+ | `web42 pack --dry-run` | Preview packaged files without writing |
109
+ | `web42 pack` | Bundle into `.web42/` directory |
110
+ | `web42 push` | Pack (if needed) and upload to marketplace |
111
+ | `web42 pull` | Fetch latest published files back locally |
112
+
113
+ ## Resources
114
+
115
+ ### References
116
+ - **`references/manifest-fields.md`** — Complete manifest.json field reference with types, constraints, and guidance.
117
+ - **`references/file-hygiene.md`** — Checklist of files and patterns to audit before packing.
118
+
119
+ ### Assets
120
+ - **`assets/readme-template.md`** — Inspirational README template for the marketplace storefront.
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "web42-publish-prep",
3
+ "tagline": "Prepare your agent for the Web42 marketplace",
4
+ "description": "Guides agents through the full publish lifecycle: init, manifest enrichment, README writing, file auditing, and validation before pushing to the Web42 marketplace.",
5
+ "category": "development",
6
+ "tags": ["web42", "marketplace", "publishing", "cli", "agent-packaging"],
7
+ "version": "1.0.0",
8
+ "license": "MIT",
9
+ "pricing": "free",
10
+ "support_url": "https://github.com/web42-ai/web42-marketplace/issues",
11
+ "homepage": "https://web42.ai/docs/publishing",
12
+ "requiredConfigPaths": [],
13
+ "primaryCredential": null,
14
+ "requires": {
15
+ "anyBins": ["web42"]
16
+ }
17
+ }
@@ -0,0 +1,57 @@
1
+ # {Agent Name}
2
+
3
+ <!--
4
+ This is a starting point, not a form. Rewrite it, restructure it, make it yours.
5
+ The marketplace renders full Markdown — use it. GIFs, videos, screenshots, emoji, whatever tells your story.
6
+ -->
7
+
8
+ {A bold opening line. What changes for the user when they have you? Don't describe yourself — describe the outcome.}
9
+
10
+ <!-- Optional: embed a GIF or demo video here -->
11
+ <!-- ![Demo](https://your-demo-url.gif) -->
12
+
13
+ ---
14
+
15
+ ## What I Do
16
+
17
+ {2–3 sentences, max. What's your superpower? Write this like you're explaining to a friend, not a spec sheet.}
18
+
19
+ ## Try Me
20
+
21
+ {3–5 concrete scenarios. Not features — experiences. Make the reader feel what it's like to work with you.}
22
+
23
+ - **"Draft my weekly standup notes from yesterday's git commits and Slack threads."**
24
+ - **"Summarize this 40-page PDF into a one-page brief I can send to my team."**
25
+ - **"Monitor my inbox and ping me only when something actually matters."**
26
+
27
+ <!-- Replace these with real scenarios that match what you actually do. -->
28
+
29
+ ## Quickstart
30
+
31
+ ```bash
32
+ web42 openclaw install @{author}/{name}
33
+ ```
34
+
35
+ {One sentence on what happens after install. Does the agent need a restart? A quick config? A first conversation?}
36
+
37
+ ## Configuration
38
+
39
+ {List any API keys, tokens, or setup the user needs to provide. Be specific about where to find each one.}
40
+
41
+ | Variable | What It Is | Where to Get It |
42
+ |----------|-----------|-----------------|
43
+ | `EXAMPLE_API_KEY` | Access token for Example API | [Example Dashboard → Settings → API](https://example.com/settings) |
44
+
45
+ <!-- Remove this section entirely if the agent needs no configuration. -->
46
+
47
+ ---
48
+
49
+ <!--
50
+ Optional sections you might add:
51
+ - "How I Work" (high-level, no secrets — just enough to build trust)
52
+ - "Limitations" (honesty builds credibility)
53
+ - "Changelog" (what's new in this version)
54
+ - "Credits" (shoutouts, inspirations)
55
+
56
+ Or make up your own sections. There are no rules here.
57
+ -->
@@ -0,0 +1,88 @@
1
+ # File Hygiene Checklist
2
+
3
+ Before packing, audit the workspace for files that should not ship to buyers. The CLI's pack command automatically excludes some patterns, but manual review catches everything else.
4
+
5
+ ## Automatically Excluded by the CLI
6
+
7
+ These patterns are hardcoded in the pack command and will never appear in the `.web42/` artifact:
8
+
9
+ | Pattern | Reason |
10
+ |---------|--------|
11
+ | `auth-profiles.json` | Platform authentication credentials |
12
+ | `MEMORY.md` | Creator's long-term memory — personal context |
13
+ | `memory/**` | Daily memory logs — personal context |
14
+ | `sessions/**` | Session history — personal context |
15
+ | `.git/**` | Version control internals |
16
+ | `node_modules/**` | Dependencies (not portable) |
17
+ | `.DS_Store` | macOS filesystem metadata |
18
+ | `*.log` | Log files |
19
+ | `openclaw.json` | Platform config (contains agent bindings, channel secrets) |
20
+ | `.openclaw/credentials/**` | Platform credentials |
21
+ | `.web42/**` | Previous pack artifacts |
22
+ | `.web42ignore` | Pack ignore config (meta, not content) |
23
+ | `manifest.json` | Shipped separately as structured data |
24
+ | `USER.md` | Always rewritten with a blank template on install |
25
+
26
+ ## Files to Flag for Manual Review
27
+
28
+ These are NOT auto-excluded but often contain content that should not ship:
29
+
30
+ ### Personal Data
31
+
32
+ - **`HEARTBEAT.md`** — If it contains creator-specific tasks, reminders, or routines. Reset to the scaffold default (empty with comments) unless the tasks are part of the agent's intended behavior.
33
+ - **`SOUL.md`** — If it references the creator by name, contains personal preferences, or has inside jokes. Generalize to describe the agent's intended persona, not the creator's personality.
34
+ - **`IDENTITY.md`** — If it contains the creator's chosen name/emoji/avatar. The buyer's agent should form its own identity. Reset to the scaffold template or write a persona description that fits the agent's purpose.
35
+ - **`TOOLS.md`** — If it contains the creator's SSH hosts, camera names, device nicknames, etc. Reset to the scaffold template with example placeholders.
36
+
37
+ ### Secrets and Credentials
38
+
39
+ - **`.env` / `.env.local`** — Should never be in the workspace root. If present, flag immediately.
40
+ - **`.web42.config.json`** — Contains config variable values from the creator's install. Must not ship.
41
+ - **Hardcoded API keys in skill files** — The CLI strips known patterns (`sk-...`, `ghp_...`, bearer tokens), but custom keys may slip through. Grep for suspicious patterns: long hex/base64 strings, `token`, `secret`, `password`, `apikey`.
42
+
43
+ ### Development Artifacts
44
+
45
+ - **`.vscode/` / `.cursor/` / `.idea/`** — IDE configuration. Not relevant to buyers.
46
+ - **`__pycache__/` / `*.pyc`** — Python bytecode.
47
+ - **`Thumbs.db`** — Windows thumbnail cache.
48
+ - **`*.bak` / `*.swp` / `*.tmp`** — Editor backup/swap files.
49
+ - **`test/` / `tests/` / `__tests__/`** — Test files, unless they are part of the agent's functionality.
50
+ - **Build outputs** — `dist/`, `build/`, `out/` directories.
51
+
52
+ ### Large or Binary Files
53
+
54
+ - The pack command skips files larger than 1 MB.
55
+ - Binary files (images, compiled executables) are skipped automatically (UTF-8 decode failure).
56
+ - If the agent needs images (e.g., for the README cover), use `coverImage` in the manifest or host them externally.
57
+
58
+ ## Using `.web42ignore`
59
+
60
+ Create a `.web42ignore` file in the workspace root to exclude additional patterns. Syntax follows `.gitignore`:
61
+
62
+ ```
63
+ # Exclude test fixtures
64
+ tests/**
65
+ fixtures/**
66
+
67
+ # Exclude draft documents
68
+ drafts/**
69
+
70
+ # Exclude local scripts not part of the agent
71
+ scripts/local-*.sh
72
+ ```
73
+
74
+ The `.web42ignore` file itself is automatically excluded from the artifact.
75
+
76
+ ## Verification
77
+
78
+ After auditing, always run:
79
+
80
+ ```
81
+ web42 pack --dry-run
82
+ ```
83
+
84
+ This prints every file that would be included. Review the list for:
85
+
86
+ 1. **Unexpected files** — anything you don't recognize or didn't intend to ship
87
+ 2. **File count** — a typical agent has 5–30 files. Hundreds of files suggests something is wrong.
88
+ 3. **Sensitive content** — spot-check a few files for leaked secrets or personal data
@@ -0,0 +1,139 @@
1
+ # manifest.json Field Reference
2
+
3
+ The manifest describes your agent package. Format version is always `"agentpkg/1"`.
4
+
5
+ ## Required Fields
6
+
7
+ ### `name` (string)
8
+
9
+ The package identifier. Appears in install commands and URLs.
10
+
11
+ - **Constraints:** 1–100 characters. Lowercase alphanumeric with hyphens only. Must start with a letter or number. Regex: `^[a-z0-9][a-z0-9-]*$`
12
+ - **Good:** `support-bot`, `code-reviewer`, `daily-digest`
13
+ - **Bad:** `My_Agent`, `Support Bot`, `-agent`
14
+ - **Guidance:** Pick something short, memorable, and descriptive of what the agent does. This becomes the slug in `@author/name`.
15
+
16
+ ### `description` (string)
17
+
18
+ A short pitch for the agent. Shown in search results and the marketplace listing.
19
+
20
+ - **Constraints:** 1–500 characters.
21
+ - **Good:** "Drafts weekly team reports from your CRM data and posts them to Slack every Monday."
22
+ - **Bad:** "An AI agent." / "This agent uses GPT-4 to process natural language queries against a database."
23
+ - **Guidance:** Lead with the benefit to the user. What problem disappears? Avoid technical jargon about how it works internally.
24
+
25
+ ### `version` (string)
26
+
27
+ Semantic version of the package.
28
+
29
+ - **Constraints:** Must match `MAJOR.MINOR.PATCH` (e.g., `1.0.0`).
30
+ - **Guidance:** Start at `1.0.0` for first publish. Bump `PATCH` for fixes, `MINOR` for new capabilities, `MAJOR` for breaking changes to config or behavior.
31
+
32
+ ### `author` (string)
33
+
34
+ Your Web42 username. Set automatically by `web42 init` from your auth credentials.
35
+
36
+ - **Constraints:** Non-empty string.
37
+ - **Guidance:** Don't edit manually — it's populated from `web42 auth whoami`.
38
+
39
+ ## Optional Fields
40
+
41
+ ### `platform` (string)
42
+
43
+ Target agent platform.
44
+
45
+ - **Values:** Currently only `"openclaw"`.
46
+ - **Guidance:** Set during `web42 init` based on the platform prompt.
47
+
48
+ ### `skills` (array)
49
+
50
+ List of skills the agent provides. Each entry has `name` (string) and `description` (string).
51
+
52
+ - **Auto-detected** from `skills/*/SKILL.md` during init and pack.
53
+ - **Guidance:** Don't edit manually. Add skills by creating `skills/<name>/SKILL.md` in your workspace. Internal skills (with `internal: true` in frontmatter) are automatically excluded.
54
+
55
+ ### `plugins` (string array)
56
+
57
+ Reserved for future use.
58
+
59
+ - **Default:** `[]`
60
+ - **Guidance:** Leave empty for now.
61
+
62
+ ### `modelPreferences` (object)
63
+
64
+ Preferred LLM models for this agent.
65
+
66
+ - **Fields:** `primary` (string, optional), `fallback` (string, optional)
67
+ - **Example:** `{ "primary": "claude-sonnet-4-20250514" }`
68
+ - **Guidance:** Set `primary` to the model the agent is designed and tested for. The `fallback` is used if the primary is unavailable. During install, the CLI will prompt buyers for the corresponding provider API key.
69
+
70
+ ### `tags` (string array)
71
+
72
+ Searchable labels for marketplace discoverability.
73
+
74
+ - **Default:** `[]`
75
+ - **Good:** `["support", "crm", "slack", "weekly-reports"]`
76
+ - **Bad:** `["ai", "agent", "good"]` (too generic)
77
+ - **Guidance:** 3–6 tags. Think about what a buyer would search for. Mix category terms ("support", "finance") with capability terms ("slack-integration", "pdf-generation").
78
+
79
+ ### `coverImage` (string)
80
+
81
+ Path to a cover image file, relative to workspace root.
82
+
83
+ - **Guidance:** Optional but recommended. A good cover image dramatically improves click-through on the marketplace. Use a 1200x630 or 1200x1200 image.
84
+
85
+ ### `demoVideoUrl` (string)
86
+
87
+ URL to a demo video.
88
+
89
+ - **Constraints:** Must be a valid URL.
90
+ - **Guidance:** A 1–3 minute video showing the agent in action converts far better than text alone. Host on YouTube, Loom, or similar.
91
+
92
+ ### `configVariables` (array)
93
+
94
+ Secrets and configuration values that buyers provide during install.
95
+
96
+ - **Each entry:** `{ key, label, description?, required, default? }`
97
+ - `key` — Environment variable name (e.g., `SLACK_BOT_TOKEN`)
98
+ - `label` — Human-readable name shown in the install prompt (e.g., "Slack Bot Token")
99
+ - `description` — Optional help text explaining where to find this value
100
+ - `required` — Whether install should block without it
101
+ - `default` — Optional default value
102
+ - **Auto-detected** from skill files during pack (secrets are stripped and replaced with placeholders).
103
+ - **Guidance:** For each config variable, make the `label` and `description` crystal clear. A buyer who has never seen your agent should understand exactly what to provide and where to get it.
104
+
105
+ ## Example Manifest
106
+
107
+ ```json
108
+ {
109
+ "format": "agentpkg/1",
110
+ "platform": "openclaw",
111
+ "name": "weekly-digest",
112
+ "description": "Summarizes your team's CRM activity and posts a digest to Slack every Monday morning.",
113
+ "version": "1.0.0",
114
+ "author": "alice",
115
+ "skills": [
116
+ { "name": "crm-reader", "description": "Query CRM data for weekly activity" },
117
+ { "name": "slack-poster", "description": "Post formatted messages to Slack channels" }
118
+ ],
119
+ "plugins": [],
120
+ "modelPreferences": { "primary": "claude-sonnet-4-20250514" },
121
+ "tags": ["crm", "slack", "weekly-reports", "productivity"],
122
+ "coverImage": "assets/cover.png",
123
+ "demoVideoUrl": "https://www.youtube.com/watch?v=example",
124
+ "configVariables": [
125
+ {
126
+ "key": "CRM_API_KEY",
127
+ "label": "CRM API Key",
128
+ "description": "Found in your CRM dashboard under Settings > API",
129
+ "required": true
130
+ },
131
+ {
132
+ "key": "SLACK_BOT_TOKEN",
133
+ "label": "Slack Bot Token",
134
+ "description": "Create a Slack app at api.slack.com and copy the Bot User OAuth Token",
135
+ "required": true
136
+ }
137
+ ]
138
+ }
139
+ ```