[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6KVSYJMC479SPZ85QMB697N":3,"skill-same:01M6KVSYJMC479SPZ85QMB697N":84},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":47,"commitSha":48,"skillDirectory":49,"forksCount":50,"repositoryHtmlUrl":51,"repositoryHomepageUrl":52,"ownerHtmlUrl":53,"ownerBlogUrl":54,"ownerDescription":6,"updatedAt":55,"install":56,"resources":69},"01M6KVSYJMC479SPZ85QMB697N","adk-prompt-engineering",null,"Writing effective ADK system prompts — dynamic instructions with InstructionProvider, state placeholders, context injection, tone\u002Fstyle sections. Load this skill when creating or improving an agent's system prompt.","Folken2\u002Fnuvel","Folken2","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F175213316?v=4","01M6KVPA04RKNPCC04H2G96FAS","Albert Folch","01M6KVPA43VNTA4PXSEB1TCD81",2,"MIT","https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fnuvel\u002Fbackends\u002Fadk\u002Fskills\u002Fadk-prompt-engineering\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"prompt engineering","adk prompt engineering","prompt","engineering","adk","state","injection","system","context","instructions","prompts","tone","style","with","system prompt","load","system prompts","writing","2026-11-10 10:12:30",false,"---\nname: adk-prompt-engineering\ndescription: >\n  Writing effective ADK system prompts — dynamic instructions with\n  InstructionProvider, state placeholders, context injection, tone\u002Fstyle\n  sections. Load this skill when creating or improving an agent's system prompt.\n---\n\n# ADK Prompt Engineering\n\n**Version 1.0** | 2026-04-04\n\nWrite production-quality system prompts for Google ADK agents. This skill\ncovers prompt structure, dynamic instructions, state injection, and templates\nfor common agent types.\n\n## System Prompt Structure\n\nEvery ADK agent prompt should follow this structure, in order:\n\n```\n1. IDENTITY        — Who the agent is, its name, role, and expertise\n2. CAPABILITIES    — What the agent can do (and what it cannot)\n3. WORKFLOW        — Step-by-step process for handling requests\n4. TOOLS           — Documentation for each tool: when to use, parameters, examples\n5. RULES           — Behavioral constraints and guidelines\n6. GUARDRAILS      — Safety limits, forbidden actions, escalation triggers\n```\n\n### Section 1: Identity\n\nLead with a clear, specific identity statement. This anchors the LLM's\nbehavior more than any other section.\n\n```\nYou are {agent_name}, a {role} specialized in {domain}.\n\nYou work for {company\u002Fcontext} and help users with {primary_task}.\n```\n\n**Do:**\n- Be specific: \"a senior data analyst\" not \"an assistant\"\n- Include domain: \"specialized in SQL analytics and visualization\"\n- Set expertise level: \"You have deep expertise in...\"\n\n**Don't:**\n- Use generic identity: \"You are a helpful AI assistant\"\n- Omit the domain — the LLM will default to general-purpose behavior\n\n### Section 2: Capabilities\n\nExplicitly list what the agent can and cannot do. This prevents hallucinated\ncapabilities and sets user expectations.\n\n```\n## Capabilities\n\nYou CAN:\n- Query databases using SQL via the execute_sql tool\n- Create charts and visualizations\n- Export results to CSV\n\nYou CANNOT:\n- Modify or delete data in the database\n- Access external APIs or the internet\n- Execute arbitrary code\n```\n\n### Section 3: Workflow\n\nProvide a numbered step-by-step process. This is the most impactful section\nfor consistent agent behavior.\n\n```\n## Workflow\n\nWhen a user makes a request, follow these steps:\n\n1. **Understand**: Clarify the request if ambiguous. Identify the data needed.\n2. **Plan**: Determine which tables and queries are needed. Share the plan.\n3. **Execute**: Run SQL queries using execute_sql. Check results for errors.\n4. **Analyze**: Interpret the results. Look for patterns and outliers.\n5. **Present**: Format results as a clear summary with charts if appropriate.\n6. **Follow up**: Ask if the user needs refinements or additional analysis.\n```\n\n**Key principle:** The workflow should describe the agent's _thinking process_,\nnot just list actions. Include decision points (\"if ambiguous, clarify first\").\n\n### Section 4: Tools\n\nDocument each tool the agent has access to. The LLM needs to know _when_ to\nuse each tool, not just that it exists.\n\n```\n## Tools\n\n### execute_sql\n- **When to use**: For any data retrieval or analysis that requires querying the database\n- **Parameters**: `query` (string) — a valid PostgreSQL query\n- **Notes**: Read-only access. Queries timeout after 30s. Always use LIMIT for exploration.\n- **Example**: `execute_sql(query=\"SELECT count(*) FROM orders WHERE status = 'pending'\")`\n\n### create_chart\n- **When to use**: When the user requests a visualization or when data would benefit from a chart\n- **Parameters**: `chart_type` (bar|line|pie), `data` (JSON), `title` (string)\n- **Notes**: Prefer bar charts for comparisons, line for trends, pie for proportions (\u003C6 categories).\n```\n\n**Key principle:** Explain the _decision criteria_ for using each tool, not\njust the API. \"When to use\" is more important than parameter documentation.\n\n### Section 5: Rules\n\nBehavioral guidelines that shape the agent's style and approach.\n\n```\n## Rules\n\n- Always show your SQL queries before executing them\n- Use markdown tables for structured data (under 20 rows)\n- Round numbers to 2 decimal places unless precision matters\n- When results are unexpected, explain possible reasons\n- Respond in the same language the user uses\n```\n\n### Section 6: Guardrails\n\nHard limits that the agent must never violate. Put these last — they serve as\na \"final check\" anchor.\n\n```\n## Guardrails\n\n- NEVER execute DELETE, UPDATE, INSERT, or DROP statements\n- NEVER expose raw database credentials or connection strings\n- NEVER share data from one user's session with another\n- If a query would return more than 10,000 rows, ask for filters first\n- If uncertain about data sensitivity, ask the user before displaying\n```\n\n## Dynamic vs Static Prompts\n\n### Static Prompts (Default)\n\nUse a plain string for the `instruction` parameter. Best for agents with\nfixed behavior.\n\n```python\nagent = LlmAgent(\n    name=\"analyst\",\n    model=\"gemini-2.5-flash\",\n    instruction=\"You are a data analyst. ...\",\n)\n```\n\n### State Placeholders\n\nADK automatically replaces `{key}` placeholders in the instruction string\nwith values from `session.state`. Use these for injecting dynamic context\nwithout a full InstructionProvider.\n\n```python\nagent = LlmAgent(\n    name=\"analyst\",\n    model=\"gemini-2.5-flash\",\n    instruction=\"\"\"You are a data analyst for {company_name}.\n\nCurrent user: {user_name} (role: {user_role})\nCurrent mode: {mode}\n\nAvailable datasets: {available_datasets}\n\"\"\",\n)\n```\n\nFor details on state placeholders and prefixes, load:\n`load_skill_resource(\"adk-prompt-engineering\", \"references\u002Fstate-placeholders.md\")`\n\n### InstructionProvider (Dynamic)\n\nUse an async function that receives `ReadonlyContext` and returns the full\nprompt string. Best for prompts that need to:\n- Load external context files\n- Build tool documentation dynamically\n- Change behavior based on complex state logic\n\n```python\nasync def get_instruction(ctx) -> str:\n    mode = ctx.state.get(\"mode\", \"default\")\n    # ... build prompt dynamically\n    return full_prompt_string\n\nagent = LlmAgent(\n    name=\"analyst\",\n    model=\"gemini-2.5-flash\",\n    instruction=get_instruction,\n)\n```\n\nFor the complete InstructionProvider pattern with context file loading, load:\n`load_skill_resource(\"adk-prompt-engineering\", \"references\u002Finstruction-provider-pattern.md\")`\n\n## Context Injection Pattern\n\nFor agents that need substantial reference material, use a `contexts\u002F`\ndirectory pattern:\n\n```\nagent_package\u002F\n  contexts\u002F\n    domain_knowledge.md\n    style_guide.md\n    tool_reference.md\n  agent.py\n```\n\nLoad contexts in the InstructionProvider:\n\n```python\nfrom pathlib import Path\n\nCONTEXTS_DIR = Path(__file__).parent \u002F \"contexts\"\n\nasync def get_instruction(ctx) -> str:\n    domain = (CONTEXTS_DIR \u002F \"domain_knowledge.md\").read_text()\n    style = (CONTEXTS_DIR \u002F \"style_guide.md\").read_text()\n\n    return f\"\"\"You are an analyst.\n\n## Domain Knowledge\n{domain}\n\n## Style Guide\n{style}\n\n## Current Session\nUser: {ctx.state.get('user_name', 'Unknown')}\n\"\"\"\n```\n\n**Benefits:**\n- Context files are version-controlled and reviewable\n- Non-engineers can edit domain knowledge without touching Python\n- Prompts stay readable — large reference blocks live in separate files\n\n## The three prompt tiers (cache stability)\n\nEvery agent scaffolded by nuvel assembles its system prompt as an\n`InstructionProvider` that builds three tiers, concatenated in this fixed\norder (`prompt\u002Finstructions.py.tmpl`):\n\n1. **Stable** — `build_stable_tier()`: static identity\u002Fpersona (the persona\n   scaffold, SOUL.md, and the system frame). Byte-identical across turns\n   within a session — nothing in this tier is allowed to vary turn to turn.\n2. **Session** — `build_session_tier(ctx)`: session-specific but\n   slow-changing — the structured user-profile block plus memory retrieved\n   for the current conversation (relevance-conditioned, not the whole\n   memory file). Changes only when the underlying profile or retrieved\n   memory actually changes.\n3. **Volatile** — `build_volatile_tier(ctx)`: per-turn reminders (today's\n   date, an infra warning, the last tool error, a near-budget notice).\n   Rides the tail of the prompt and is expected to differ every turn.\n\n`get_agent_instruction(ctx)` returns `\"\\n\\n\".join([stable, session, volatile])`\n(skipping any empty tier) — stable always leads, volatile always trails.\n\n**Why the ordering is a cost decision, not a formatting one.** Providers\ncache on prompt *prefix*: a cache hit costs a fraction of a fresh input\ntoken, but the cache only stays warm while the leading bytes of the prompt\nstay identical. Put anything per-turn near the front — a timestamp, a\nturn counter, an error message — and you invalidate the cached prefix on\nevery single turn, silently multiplying input-token cost with no change in\nbehavior. Ordering stable-then-session-then-volatile is what keeps the\nexpensive, rarely-changing identity\u002Fpersona text cache-hot turn after turn\nwhile only the cheap tail pays for freshness. This matters most for exactly\nthe agents nuvel targets: long stable personas plus heavy retrieved memory,\nrun over many turns.\n\n**The authoring contract.** When adding instruction content to a generated\nagent, decide which tier it belongs to and don't mix them:\n\n- New persona text, tone rules, or identity content → the **stable** tier.\n- Anything derived from session state (user profile fields, retrieved\n  memory) → the **session** tier.\n- Anything that changes every turn (dates, warnings, error nudges, budget\n  notices) → the **volatile** tier.\n- **Never interpolate a per-turn value into the stable tier** — that's the\n  one mistake that defeats the whole scheme, since it makes the \"stable\"\n  prefix move on every turn anyway.\n\n**Graceful degradation.** `build_session_tier` wraps each source\nindependently in `try`\u002F`except`: if the user-profile store or the memory\nretrieval call fails, that section is simply omitted rather than raising —\nthe session tier degrades to whatever sources succeeded (down to empty)\ninstead of breaking prompt assembly for the whole turn\n(`test_session_tier_degrades_when_sources_fail`).\n\nThis contract is pinned by the 11 tests in `tests\u002Ftest_prompt_tiers.py` —\nin particular `test_full_prompt_stable_prefix_survives_volatile_change` and\n`test_stable_tier_ignores_volatile_state` assert that changing only volatile\nstate leaves the stable prefix byte-identical. A future edit that breaks\ntier isolation fails that suite.\n\nEvent compaction (see `adk-long-horizon-sessions`) is a structurally\nseparate mechanism — it rewrites the session's *event* history, not the\nsystem-instruction tiers described here, and `instructions.py.tmpl` never\nreads events or does any compaction-related work. The two are independent\nlevers on the same turn's total cost: compaction buys headroom on the event\nside of the ledger, a byte-identical stable prefix buys a cheap prompt on\nthe instruction side. Tune them as two separate cost decisions, not one\nfeeding the other.\n\n## Tool Documentation Best Practices\n\nWhen an agent has many tools, dedicate a section of the prompt to explaining\ndecision criteria:\n\n```\n## When to Use Each Tool\n\nUse this decision tree:\n\nNeed data from the database? → execute_sql\nNeed to create a chart? → create_chart\nNeed to export results? → export_csv\nNeed to send a notification? → send_alert\nUnsure? → Ask the user what they need\n\n### Tool Interaction Patterns\n\n1. Always query data BEFORE creating charts (you need the data first)\n2. After any SQL error, explain the error and suggest a fix\n3. Only send alerts when the user explicitly requests them\n```\n\n## Prompt Templates\n\nFor complete, production-ready prompt templates for common agent types, load:\n`load_skill_resource(\"adk-prompt-engineering\", \"references\u002Fprompt-templates.md\")`\n\n## Common Mistakes\n\n| Mistake | Fix |\n|---------|-----|\n| Generic identity (\"helpful assistant\") | Be specific: role, domain, expertise level |\n| No workflow section | Add numbered steps — this drives consistent behavior |\n| Tools listed without \"when to use\" | Add decision criteria for every tool |\n| Guardrails buried in the middle | Put guardrails last for anchoring effect |\n| Prompt over 4000 tokens | Move reference material to context files |\n| No capability boundaries | Explicitly list what the agent CANNOT do |\n| State placeholders without defaults | Use `ctx.state.get(\"key\", \"default\")` in InstructionProvider |\n| Mixing concerns in one section | Keep identity, workflow, tools, and rules in separate sections |\n","# ADK Prompt Engineering\n\n**Version 1.0** | 2026-04-04\n\nWrite production-quality system prompts for Google ADK agents. This skill\ncovers prompt structure, dynamic instructions, state injection, and templates\nfor common agent types.\n\n## System Prompt Structure\n\nEvery ADK agent prompt should follow this structure, in order:\n\n```\n1. IDENTITY        — Who the agent is, its name, role, and expertise\n2. CAPABILITIES    — What the agent can do (and what it cannot)\n3. WORKFLOW        — Step-by-step process for handling requests\n4. TOOLS           — Documentation for each tool: when to use, parameters, examples\n5. RULES           — Behavioral constraints and guidelines\n6. GUARDRAILS      — Safety limits, forbidden actions, escalation triggers\n```\n\n### Section 1: Identity\n\nLead with a clear, specific identity statement. This anchors the LLM's\nbehavior more than any other section.\n\n```\nYou are {agent_name}, a {role} specialized in {domain}.\n\nYou work for {company\u002Fcontext} and help users with {primary_task}.\n```\n\n**Do:**\n- Be specific: \"a senior data analyst\" not \"an assistant\"\n- Include domain: \"specialized in SQL analytics and visualization\"\n- Set expertise level: \"You have deep expertise in...\"\n\n**Don't:**\n- Use generic identity: \"You are a helpful AI assistant\"\n- Omit the domain — the LLM will default to general-purpose behavior\n\n### Section 2: Capabilities\n\nExplicitly list what the agent can and cannot do. This prevents hallucinated\ncapabilities and sets user expectations.\n\n```\n## Capabilities\n\nYou CAN:\n- Query databases using SQL via the execute_sql tool\n- Create charts and visualizations\n- Export results to CSV\n\nYou CANNOT:\n- Modify or delete data in the database\n- Access external APIs or the internet\n- Execute arbitrary code\n```\n\n### Section 3: Workflow\n\nProvide a numbered step-by-step process. This is the most impactful section\nfor consistent agent behavior.\n\n```\n## Workflow\n\nWhen a user makes a request, follow these steps:\n\n1. **Understand**: Clarify the request if ambiguous. Identify the data needed.\n2. **Plan**: Determine which tables and queries are needed. Share the plan.\n3. **Execute**: Run SQL queries using execute_sql. Check results for errors.\n4. **Analyze**: Interpret the results. Look for patterns and outliers.\n5. **Present**: Format results as a clear summary with charts if appropriate.\n6. **Follow up**: Ask if the user needs refinements or additional analysis.\n```\n\n**Key principle:** The workflow should describe the agent's _thinking process_,\nnot just list actions. Include decision points (\"if ambiguous, clarify first\").\n\n### Section 4: Tools\n\nDocument each tool the agent has access to. The LLM needs to know _when_ to\nuse each tool, not just that it exists.\n\n```\n## Tools\n\n### execute_sql\n- **When to use**: For any data retrieval or analysis that requires querying the database\n- **Parameters**: `query` (string) — a valid PostgreSQL query\n- **Notes**: Read-only access. Queries timeout after 30s. Always use LIMIT for exploration.\n- **Example**: `execute_sql(query=\"SELECT count(*) FROM orders WHERE status = 'pending'\")`\n\n### create_chart\n- **When to use**: When the user requests a visualization or when data would benefit from a chart\n- **Parameters**: `chart_type` (bar|line|pie), `data` (JSON), `title` (string)\n- **Notes**: Prefer bar charts for comparisons, line for trends, pie for proportions (\u003C6 categories).\n```\n\n**Key principle:** Explain the _decision criteria_ for using each tool, not\njust the API. \"When to use\" is more important than parameter documentation.\n\n### Section 5: Rules\n\nBehavioral guidelines that shape the agent's style and approach.\n\n```\n## Rules\n\n- Always show your SQL queries before executing them\n- Use markdown tables for structured data (under 20 rows)\n- Round numbers to 2 decimal places unless precision matters\n- When results are unexpected, explain possible reasons\n- Respond in the same language the user uses\n```\n\n### Section 6: Guardrails\n\nHard limits that the agent must never violate. Put these last — they serve as\na \"final check\" anchor.\n\n```\n## Guardrails\n\n- NEVER execute DELETE, UPDATE, INSERT, or DROP statements\n- NEVER expose raw database credentials or connection strings\n- NEVER share data from one user's session with another\n- If a query would return more than 10,000 rows, ask for filters first\n- If uncertain about data sensitivity, ask the user before displaying\n```\n\n## Dynamic vs Static Prompts\n\n### Static Prompts (Default)\n\nUse a plain string for the `instruction` parameter. Best for agents with\nfixed behavior.\n\n```python\nagent = LlmAgent(\n    name=\"analyst\",\n    model=\"gemini-2.5-flash\",\n    instruction=\"You are a data analyst. ...\",\n)\n```\n\n### State Placeholders\n\nADK automatically replaces `{key}` placeholders in the instruction string\nwith values from `session.state`. Use these for injecting dynamic context\nwithout a full InstructionProvider.\n\n```python\nagent = LlmAgent(\n    name=\"analyst\",\n    model=\"gemini-2.5-flash\",\n    instruction=\"\"\"You are a data analyst for {company_name}.\n\nCurrent user: {user_name} (role: {user_role})\nCurrent mode: {mode}\n\nAvailable datasets: {available_datasets}\n\"\"\",\n)\n```\n\nFor details on state placeholders and prefixes, load:\n`load_skill_resource(\"adk-prompt-engineering\", \"references\u002Fstate-placeholders.md\")`\n\n### InstructionProvider (Dynamic)\n\nUse an async function that receives `ReadonlyContext` and returns the full\nprompt string. Best for prompts that need to:\n- Load external context files\n- Build tool documentation dynamically\n- Change behavior based on complex state logic\n\n```python\nasync def get_instruction(ctx) -> str:\n    mode = ctx.state.get(\"mode\", \"default\")\n    # ... build prompt dynamically\n    return full_prompt_string\n\nagent = LlmAgent(\n    name=\"analyst\",\n    model=\"gemini-2.5-flash\",\n    instruction=get_instruction,\n)\n```\n\nFor the complete InstructionProvider pattern with context file loading, load:\n`load_skill_resource(\"adk-prompt-engineering\", \"references\u002Finstruction-provider-pattern.md\")`\n\n## Context Injection Pattern\n\nFor agents that need substantial reference material, use a `contexts\u002F`\ndirectory pattern:\n\n```\nagent_package\u002F\n  contexts\u002F\n    domain_knowledge.md\n    style_guide.md\n    tool_reference.md\n  agent.py\n```\n\nLoad contexts in the InstructionProvider:\n\n```python\nfrom pathlib import Path\n\nCONTEXTS_DIR = Path(__file__).parent \u002F \"contexts\"\n\nasync def get_instruction(ctx) -> str:\n    domain = (CONTEXTS_DIR \u002F \"domain_knowledge.md\").read_text()\n    style = (CONTEXTS_DIR \u002F \"style_guide.md\").read_text()\n\n    return f\"\"\"You are an analyst.\n\n## Domain Knowledge\n{domain}\n\n## Style Guide\n{style}\n\n## Current Session\nUser: {ctx.state.get('user_name', 'Unknown')}\n\"\"\"\n```\n\n**Benefits:**\n- Context files are version-controlled and reviewable\n- Non-engineers can edit domain knowledge without touching Python\n- Prompts stay readable — large reference blocks live in separate files\n\n## The three prompt tiers (cache stability)\n\nEvery agent scaffolded by nuvel assembles its system prompt as an\n`InstructionProvider` that builds three tiers, concatenated in this fixed\norder (`prompt\u002Finstructions.py.tmpl`):\n\n1. **Stable** — `build_stable_tier()`: static identity\u002Fpersona (the persona\n   scaffold, SOUL.md, and the system frame). Byte-identical across turns\n   within a session — nothing in this tier is allowed to vary turn to turn.\n2. **Session** — `build_session_tier(ctx)`: session-specific but\n   slow-changing — the structured user-profile block plus memory retrieved\n   for the current conversation (relevance-conditioned, not the whole\n   memory file). Changes only when the underlying profile or retrieved\n   memory actually changes.\n3. **Volatile** — `build_volatile_tier(ctx)`: per-turn reminders (today's\n   date, an infra warning, the last tool error, a near-budget notice).\n   Rides the tail of the prompt and is expected to differ every turn.\n\n`get_agent_instruction(ctx)` returns `\"\\n\\n\".join([stable, session, volatile])`\n(skipping any empty tier) — stable always leads, volatile always trails.\n\n**Why the ordering is a cost decision, not a formatting one.** Providers\ncache on prompt *prefix*: a cache hit costs a fraction of a fresh input\ntoken, but the cache only stays warm while the leading bytes of the prompt\nstay identical. Put anything per-turn near the front — a timestamp, a\nturn counter, an error message — and you invalidate the cached prefix on\nevery single turn, silently multiplying input-token cost with no change in\nbehavior. Ordering stable-then-session-then-volatile is what keeps the\nexpensive, rarely-changing identity\u002Fpersona text cache-hot turn after turn\nwhile only the cheap tail pays for freshness. This matters most for exactly\nthe agents nuvel targets: long stable personas plus heavy retrieved memory,\nrun over many turns.\n\n**The authoring contract.** When adding instruction content to a generated\nagent, decide which tier it belongs to and don't mix them:\n\n- New persona text, tone rules, or identity content → the **stable** tier.\n- Anything derived from session state (user profile fields, retrieved\n  memory) → the **session** tier.\n- Anything that changes every turn (dates, warnings, error nudges, budget\n  notices) → the **volatile** tier.\n- **Never interpolate a per-turn value into the stable tier** — that's the\n  one mistake that defeats the whole scheme, since it makes the \"stable\"\n  prefix move on every turn anyway.\n\n**Graceful degradation.** `build_session_tier` wraps each source\nindependently in `try`\u002F`except`: if the user-profile store or the memory\nretrieval call fails, that section is simply omitted rather than raising —\nthe session tier degrades to whatever sources succeeded (down to empty)\ninstead of breaking prompt assembly for the whole turn\n(`test_session_tier_degrades_when_sources_fail`).\n\nThis contract is pinned by the 11 tests in `tests\u002Ftest_prompt_tiers.py` —\nin particular `test_full_prompt_stable_prefix_survives_volatile_change` and\n`test_stable_tier_ignores_volatile_state` assert that changing only volatile\nstate leaves the stable prefix byte-identical. A future edit that breaks\ntier isolation fails that suite.\n\nEvent compaction (see `adk-long-horizon-sessions`) is a structurally\nseparate mechanism — it rewrites the session's *event* history, not the\nsystem-instruction tiers described here, and `instructions.py.tmpl` never\nreads events or does any compaction-related work. The two are independent\nlevers on the same turn's total cost: compaction buys headroom on the event\nside of the ledger, a byte-identical stable prefix buys a cheap prompt on\nthe instruction side. Tune them as two separate cost decisions, not one\nfeeding the other.\n\n## Tool Documentation Best Practices\n\nWhen an agent has many tools, dedicate a section of the prompt to explaining\ndecision criteria:\n\n```\n## When to Use Each Tool\n\nUse this decision tree:\n\nNeed data from the database? → execute_sql\nNeed to create a chart? → create_chart\nNeed to export results? → export_csv\nNeed to send a notification? → send_alert\nUnsure? → Ask the user what they need\n\n### Tool Interaction Patterns\n\n1. Always query data BEFORE creating charts (you need the data first)\n2. After any SQL error, explain the error and suggest a fix\n3. Only send alerts when the user explicitly requests them\n```\n\n## Prompt Templates\n\nFor complete, production-ready prompt templates for common agent types, load:\n`load_skill_resource(\"adk-prompt-engineering\", \"references\u002Fprompt-templates.md\")`\n\n## Common Mistakes\n\n| Mistake | Fix |\n|---------|-----|\n| Generic identity (\"helpful assistant\") | Be specific: role, domain, expertise level |\n| No workflow section | Add numbered steps — this drives consistent behavior |\n| Tools listed without \"when to use\" | Add decision criteria for every tool |\n| Guardrails buried in the middle | Put guardrails last for anchoring effect |\n| Prompt over 4000 tokens | Move reference material to context files |\n| No capability boundaries | Explicitly list what the agent CANNOT do |\n| State placeholders without defaults | Use `ctx.state.get(\"key\", \"default\")` in InstructionProvider |\n| Mixing concerns in one section | Keep identity, workflow, tools, and rules in separate sections |\n",{"name":5,"description":7},"main","41d246dd855999c6bc4be528bc8d0d1b10ac8c47","nuvel\u002Fbackends\u002Fadk\u002Fskills\u002Fadk-prompt-engineering",1,"https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel","https:\u002F\u002Ffolken2.github.io\u002Fnuvel\u002F","https:\u002F\u002Fgithub.com\u002FFolken2","folch.ai","2026-11-05 22:40:38",{"source":8,"skillName":5,"commands":57,"prompt":67,"zipAvailable":68},[58,61,64],{"tool":59,"command":60},"npx","npx skills add Folken2\u002Fnuvel --skill adk-prompt-engineering",{"tool":62,"command":63},"bunx","bunx skills add Folken2\u002Fnuvel --skill adk-prompt-engineering",{"tool":65,"command":66},"pnpm","pnpm dlx skills add Folken2\u002Fnuvel --skill adk-prompt-engineering","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fnuvel\u002Fbackends\u002Fadk\u002Fskills\u002Fadk-prompt-engineering\u002FSKILL.md",true,[70,76,80],{"path":71,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":74,"sourceHtmlUrl":75},"references\u002Finstruction-provider-pattern.md","REFERENCE","参考文档",7676,"https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fnuvel\u002Fbackends\u002Fadk\u002Fskills\u002Fadk-prompt-engineering\u002Freferences\u002Finstruction-provider-pattern.md",{"path":77,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":78,"sourceHtmlUrl":79},"references\u002Fprompt-templates.md",10547,"https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fnuvel\u002Fbackends\u002Fadk\u002Fskills\u002Fadk-prompt-engineering\u002Freferences\u002Fprompt-templates.md",{"path":81,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":82,"sourceHtmlUrl":83},"references\u002Fstate-placeholders.md",6999,"https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fnuvel\u002Fbackends\u002Fadk\u002Fskills\u002Fadk-prompt-engineering\u002Freferences\u002Fstate-placeholders.md",[85,94,107,136,152,168],{"skillNo":86,"name":87,"nameZh":6,"description":88,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":89,"categories":90,"keywords":91,"publishedAt":42},"01M6KVZNJQ7AVMVBS205404CS7","greet","Greet a user warmly by name.","https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Ftests\u002Ftest_agent_plugins\u002Ffixtures\u002Fvalid-full\u002Fskills\u002Fgreet\u002FSKILL.md",[],[87,92,93],"user","name",{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":101,"publishedAt":42},"01M6KVZHYK2C9S5GRM3PZAFDXG","hello","A simple hello skill that survives a broken mcp.json.","https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Ftests\u002Ftest_agent_plugins\u002Ffixtures\u002Fbad-mcp\u002Fskills\u002Fhello\u002FSKILL.md",[100],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[96,102,103,104,105,106],"MCP","hello skill","json","broken","simple",{"skillNo":108,"name":109,"nameZh":6,"description":110,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":122,"publishedAt":42},"01M6KVZC94REQZ852EJ99ZXATK","grok-workflows","Prompt templates and workflows for using xAI GrokBot with Nuvel — code, design, research, and automated pipelines.","https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fplugins\u002Fgrokbot-plugin\u002Fskills\u002Fgrok-workflows\u002FSKILL.md",[113,116,117],{"categoryNo":114,"categoryName":115,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":118,"categoryName":119,"taxonomyType":120,"taxonomyTypeDesc":121},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[123,124,125,126,127,26,128,129,130,131,132,133,37,134,135],"workflows","grok","grok workflows","design","research","prompt templates","code","templates","xai","grokbot","pipelines","for","nuvel",{"skillNo":137,"name":138,"nameZh":6,"description":139,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":140,"categories":141,"keywords":142,"publishedAt":42},"01M6KVZ7BA5MJ1N614MTP2JXCQ","grok-setup","Configure xAI GrokBot with Nuvel API integration and project context for Nuvel-aligned development.","https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fplugins\u002Fgrokbot-plugin\u002Fskills\u002Fgrok-setup\u002FSKILL.md",[],[124,143,144,134,37,145,135,146,147,148,132,149,150,151,131,32],"grok setup","setup","project","project context","api integration","configure","development","integration","api",{"skillNo":153,"name":154,"nameZh":6,"description":155,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":156,"categories":157,"keywords":159,"publishedAt":42},"01M6KVZ3WYQ6V6XVCRE77WT2WY","cursor-setup","Configure Cursor IDE with Nuvel rules, MCP server integration, and project settings for OrgMemory-aware development.","https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fplugins\u002Fcursor-plugin\u002Fskills\u002Fcursor-setup\u002FSKILL.md",[158],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[160,161,144,150,102,162,149,163,164,148,165,166,145,37,134,167,135],"cursor","cursor setup","mcp server","server","ide","Rules","settings","project settings",{"skillNo":169,"name":170,"nameZh":6,"description":171,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":172,"categories":173,"keywords":174,"publishedAt":42},"01M6KVZ0GGSJM4AC8PK7G53H85","cursor-review","Use Cursor IDE with Nuvel OrgMemory to review changes — diff analysis, standards checking, and pre-commit review.","https:\u002F\u002Fgithub.com\u002FFolken2\u002Fnuvel\u002Fblob\u002Fmain\u002Fplugins\u002Fcursor-plugin\u002Fskills\u002Fcursor-review\u002FSKILL.md",[],[175,160,176,177,178,179,180,164,181,182,183,37,184,185,135],"cursor review","review","commit","review changes","pre-commit","analysis","use","diff","standards","changes","diff analysis"]