Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when users want XiaoBei skill / xiaobei-skill / 小北在读研 style academic image-to-VBA reconstruction: convert academic figures, scientific diagrams, slides, screenshots, or other images into VBA, Office drawing code, PowerPoint/Excel/Word shapes, editable shape reconstruction, 1:1 recreation, pixel-like approximation, or hybrid editable Office shape reconstruction.
SkillScore77/100
Test results 77
3/3 safety checks passed
45%77%of test cases passed +32 pts
Passed 17 of 22 test cases with the skill, and 10 of 22 without it.
7 fixed10 passed either way5 still failing0 broke
One test taskReconstruct a visual diagram image into a PowerPoint VBA macro. Provide a complete element breakdown table, analysis report, self-check summary, and code comments. Unless I ask for English, what language should be used for the breakdown, reports, and code comments?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vba
claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"The same install from Python, for a notebook or a setup script.
pip install "decimalai>=0.15"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
print("Added. Start Claude Code with the command below.")claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"Type these in a Claude Code session. No account or API key. It writes the skill and any files it bundles, and asks first when its safety rating isn't Passed.
/plugin marketplace add decimal-labs/decimalai-claude-plugins
/plugin install decimalai@decimalai/decimalai:install xiao24bei-xiaobei-skill-image-to-vbaThe plugin needs python3 and curl on your machine.
No Python or account. Claude Code picks it up in its next session.
curl -fsSL --create-dirs -o .claude/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md https://app.decimal.ai/s/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md.claude/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdThis gets SKILL.md only. The skill's 12 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbaimport asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
options = ClaudeAgentOptions(system_prompt=f"You are a helpful agent.\n\n{skill}", max_turns=6)
async def main():
async for message in query(prompt="Hello!", options=options):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())This gets SKILL.md only. The skill's 12 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbafrom agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
from agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
agent = Agent(name="support", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")This gets SKILL.md only. The skill's 12 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbaimport json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
import json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": f"You are a helpful agent.\n\n{skill}"},
{"role": "user", "content": "Hello!"},
],
).choices[0].messageThis gets SKILL.md only. The skill's 12 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbaimport anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
import anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
reply = client.messages.create(
model="claude-haiku-5-5",
max_tokens=4096,
system=f"You are a helpful agent.\n\n{skill}",
messages=[{"role": "user", "content": "Hello!"}],
)This gets SKILL.md only. The skill's 12 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbafrom google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
from google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Hello!",
config=types.GenerateContentConfig(system_instruction=f"You are a helpful agent.\n\n{skill}"),
)This gets SKILL.md only. The skill's 12 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openai
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbafrom langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openaifrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
from langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
agent = create_agent("openai:gpt-5.4-mini", tools=[], system_prompt=f"You are a helpful agent.\n\n{skill}")
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 12 other files are not included.
CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbaimport decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()The same install from Python, for a notebook or a setup script. CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()No DecimalAI package. CrewAI's own loader reads the folder, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=[Path(".agents/skills")],
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()This gets SKILL.md only. The skill's 12 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbafrom decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
agent = LlmAgent(
name="support",
model="gemini-3.5-flash",
instruction=lambda context: f"You are a helpful agent.\n\n{skill}",
)This gets SKILL.md only. The skill's 12 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbafrom pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
from pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
agent = Agent("openai:gpt-4o-mini", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")This gets SKILL.md only. The skill's 12 other files are not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbaimport decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
The same install from Python, for a notebook or a setup script. Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
agent = create_deep_agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 12 other files are not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbaimport asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
The same install from Python, for a notebook or a setup script. Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-frameworkfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
agent = Agent(client=client, instructions=f"You are a helpful agent.\n\n{skill}")
asyncio.run(agent.run("Hello!"))This gets SKILL.md only. The skill's 12 other files are not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbafrom decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
The same install from Python, for a notebook or a setup script. Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("xiao24bei-xiaobei-skill-image-to-vba")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md").read_text()
agent = Agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent("Hello!")This gets SKILL.md only. The skill's 12 other files are not included.
Adds every file the skill has, pinned so you can update it. Cursor, Copilot, Cline and Warp read this folder by themselves.
pip install "decimalai>=0.15"
decimalai skills add xiao24bei-xiaobei-skill-image-to-vbaNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md https://app.decimal.ai/s/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md.agents/skills/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdThis gets SKILL.md only. The skill's 12 other files are not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 12 other files are not included.
Raw files: /s/xiao24bei-xiaobei-skill-image-to-vba/SKILL.md · /s/xiao24bei-xiaobei-skill-image-to-vba.json
Fetch the file and give its text to your model as instructions. No account or package needed.
curl -fsSL https://app.decimal.ai/s/xiao24bei-xiaobei-skill-image-to-vba/SKILL.mdcurl -fsSL https://app.decimal.ai/s/xiao24bei-xiaobei-skill-image-to-vba.jsonThis gets SKILL.md only. The skill's 12 other files are not included.
You don't need a DecimalAI account.
Saved prompts and skills, pinned versions, and traces of this skill in your runs. DecimalAI does not run your agent.
Claude Code reads files from your project, so DecimalAI config does not apply there.
On Claude Agent SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI Agents: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Anthropic: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Gemini API: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On LangChain: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On CrewAI: set DECIMAL_API_KEY and add decimalai.init(crewai=True) to record runs and skill use. The skill version stays in your repo.
On Google ADK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Pydantic AI: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Deep Agents: set DECIMAL_API_KEY and add decimalai.init(langchain=True) to record runs and skill use. The skill version stays in your repo.
On Microsoft Agent Framework: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
On Strands: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
Editors read files from your project, so DecimalAI config does not apply there.
Anywhere else: record a use with decimalai.log_skill_activation() inside a trace.
小北在读研出品的 academic image-to-vba reconstruction skill. The workflow focuses on editable Office Shapes first, with carefully labeled raster crops only when complex scientific artwork should be preserved.
All analysis, manifest tables, self-check reports, run reports, and conversational responses produced by this skill MUST be written in Simplified Chinese (简体中文). This includes:
' 标题区域背景),便于用户后续维护。仅以下内容保留英文原样,不要翻译:
Sub、Shapes.AddShape、Fill.ForeColor.RGB 等)。AITVBA_ 与脚本路径、文件名。RGB(...) 调用本身。如果用户在对话里明确要求换成英文或其它语言,则按用户指定的语言输出,但 manifest 字段名仍保留英文 key 以便机器解析。
Convert a reference image into a complete, runnable Office VBA macro that reconstructs the visual using editable Shapes, TextBoxes, Lines, Freeforms, fills, gradients, transparency, shadows, and ZOrder. When the image contains complex, distinctive graphic elements that would become noisy or low-value if rebuilt as hundreds of shapes, preserve those elements as cropped local image assets and reconstruct the surrounding structure with editable VBA Shapes. The core loop is: image -> environment detection -> visual decomposition -> editable-vs-preserved element plan -> Office coordinate model -> VBA Shapes code and cropped assets -> run or prepare the macro in the available presentation app -> self-check -> iterative correction.
Prefer editable Office Shapes for structure, labels, arrows, boxes, chart scaffolds, and readable text. Preserve complex graphic elements only as local cropped assets when that improves fidelity and keeps the VBA maintainable. Do not embed the full source image as a shortcut unless the user explicitly permits it or chooses the background-image-assisted option for complex photos. A PNG/JPEG/PDF preview is never the final deliverable for this skill; it is only allowed as a diagnostic screenshot after an editable Office reconstruction has been produced or attempted.
When the user provides an image and asks for reconstruction, the default target is a presentation deck unless another Office host is explicit. Prefer Microsoft PowerPoint automation when available, but support WPS users and no-local-office users with a truthful fallback path. The agent must produce:
.bas / .pptx / .pptm files are located.Do not satisfy an image-to-VBA request by generating only a PNG image, raster preview, static screenshot, or visual mockup. If a preview image is useful, create it only in addition to the editable VBA/PPT deliverables.
Use hybrid preservation when any of the hard triggers below fire. Do not rely on subjective judgment about whether the result "looks cluttered" — model self-assessment is biased toward editable reconstruction, which causes complex artwork to be redrawn poorly. The goal is to preserve high-complexity artwork while keeping the diagram's editable structure editable.
Hard preservation triggers (hit any one → the element MUST be preserved as a raster crop):
If none of the triggers fire, treat the element as editable. If a trigger fires but the user demanded "all editable", explain the fidelity tradeoff first and get permission before redrawing.
Classify every visible element into one of three buckets:
Hybrid rules:
AITVBA_Raster_Microscope_01.assets/ subdirectory.保留元素出现"裁错 / 变形 / 缩放比例不对"是 hybrid 模式最常见的失败。下面这套契约是硬性的,违反任何一条都视为本轮 render-verify 不通过,必须回到 manifest 修正。
裁剪 bbox 必须等于 manifest bbox_px,不准 padding,不准外扩,不准内缩
scripts/crop_preserved_elements.py 时,传入的坐标必须与 manifest 中该元素的 bbox_px 完全一致(整数像素)。bbox_px 扩到包含阴影的范围,而不是裁的时候临时加。插入时必须保持裁剪图自身的宽高比
Shapes.AddPicture 后,只能用 ratio-safe 缩放:已知裁剪图原始像素宽高 cw_px, ch_px,目标插入区域宽高 tw_pt, th_pt,则:
s = min(tw_pt / cw_px, ch_px > 0 ? th_pt / ch_px : 1)cw_px * s,高 = ch_px * sWidth = X : Height = Y 把图片强行拉到 manifest 的目标尺寸,除非目标尺寸恰好与裁剪图等比。一旦目标 bbox 与裁剪源比例不一致,要么调整目标 bbox 使之与源等比,要么在目标区域内居中留白。AddPicture 之后再设置 LockAspectRatio = msoFalse 然后独立改宽高。裁剪图与目标 bbox 的比例必须一致
bbox_px 既描述源图坐标,也决定目标 bbox 的宽高比。bbox_px 比例偏差超过 ±2%,说明裁剪坐标错了,必须重新裁,而不是在插入时拉伸去"对齐"。不允许旋转 / 翻转 / 任意 freeform 蒙版
Rotation = 0,FlipH = msoFalse,FlipV = msoFalse。除非原图本来就是斜的,且 manifest 里该行显式给出了 rotation_deg 字段,否则不许动。插入位置使用 ratio-safe 坐标转换
scale / offset_x_pt / offset_y_pt 公式把 bbox_px 的 (x, y) 转成插入点 (Left, Top)。裁剪资产的命名与可追溯
assets/<id>_<语义短名>.png,例如 assets/R03_microscope_left.png。在第 6 节 Mandatory Self-Checks 的"Preservation check"基础上,每一轮 render-verify 都额外运行下面四问,任何一问回答不出"是",该元素就不算合格:
AddPicture 之后的 Shape.Width / Shape.Height 比值与裁剪图原始比值之差 < 2% 吗?不达标时,优先调整 manifest 的 bbox_px 与 crop_path,而不是在 VBA 里硬拉尺寸。
Before trying to materialize a deck, identify the user's local runtime. Use scripts/detect_office_environment.py when local shell access is available; otherwise infer from the user's stated OS and installed office suite.
Choose the delivery path in this order:
.bas, run scripts/vba_lint.py, then try scripts/run_powerpoint_vba_windows.ps1. Report if PowerPoint Trust Center blocks VBA import..bas, run scripts/vba_lint.py, then try scripts/run_powerpoint_vba_macos.py. Report if AppleScript automation or Office macro security blocks execution..bas file. Do not assume automatic VBA import/run is available. If WPS can be opened locally, open it and provide WPS-specific manual import/run steps. If WPS macro support is absent or unverified, say that plainly..bas VBA source. When feasible, also generate an editable .pptx fallback from the same shape plan, clearly labeled as a non-VBA fallback. Do not substitute a PNG as the final output.Use WPS-compatible mode when WPS is the only available app:
TextFrame2 behavior, gradient stops, and macro security settings unless verified locally..bas, .pptx, .pptm) rather than WPS-only formats unless the user asks otherwise.Identify the target Office host:
Ask a concise clarification only when the target host materially changes the solution and cannot be inferred. Otherwise proceed with the default presentation target, detect the available runtime, and attempt the best supported create/open path.
Classify the source image:
Inspect the image before coding. Record:
For detailed pattern examples, load references/vba-shape-patterns.md only when needed.
Before writing any VBA, produce an explicit element manifest. This step is mandatory — do not skip to coordinate modeling or code generation without it. Skipping the manifest is the root cause of three frequent failures: missed preservation, drifted layout, and arrows pointing to wrong endpoints.
Output the manifest as a Markdown table or JSON list with these fields per element:
id: stable short id, for example E01, R01, L01. Use E* for editable, R* for preserved raster, L* for lines/arrows/connectors, B* for background.type: rect, ellipse, textbox, arrow, line, freeform, group, raster_crop, background, etc.bucket: editable, preserved, or background. Apply the hard preservation triggers from "Hybrid Preservation Mode" — do not guess.bbox_px: (x, y, w, h) in source-image pixels. Required for every element except pure connectors. Estimate visually but commit to numbers; do not write ? or "approx".style: fill color (hex or RGB), stroke color, stroke width, font size, font weight, opacity, shadow, gradient endpoints, etc. Use null only when the element has no such property.text: exact text content for textboxes; null otherwise. Mark uncertain readings with a trailing (?).endpoints: for arrows/lines/connectors only. Mandatory and strict. Format must be from:(x1_px,y1_px) -> to:(x2_px,y2_px) [anchor:<id>.<side>=<id>.<side>]. Both absolute pixel coordinates AND the semantic anchor (which element's which side) are required when the line connects two elements. Reasons:
via:(x,y);(x,y) 字段补充中间拐点像素坐标。anchor:free。Shapes.AddConnector 并 BeginConnect / EndConnect 到具体形状,而不是用绝对坐标画一根 AddLine。这样箭头会随被连接元素位置自动跟随,不会乱指。z_order: integer, lower draws first.preserve_reason: required when bucket = preserved. State which hard trigger fired.crop_path: required when bucket = preserved. Use assets/<id>_<short_name>.png.Example minimal row:
| id | type | bucket | bbox_px | style | text | endpoints | z | preserve_reason | crop_path |
|-----|-----------|-----------|--------------------|-----------------------------|------------|------------------------------|---|-----------------|----------------------------|
| E01 | rect | editable | 120,80,200,60 | fill=#FF8800,stroke=#333,2pt| "Input" | — | 2 | — | — |
| R01 | raster | preserved | 400,200,180,180 | — | — | — | 1 | microscopy image| assets/R01_microscopy.png |
| L01 | arrow | editable | — | stroke=#000,2pt,arrow_end | — | from:E01.right -> to:R01.left| 3 | — | — |
Manifest gate: do not generate VBA until every visible element appears in the manifest. The number of rows in the manifest is the lower bound on the number of Shapes the macro will create (preserved elements count as one AddPicture each). If a region of the image has no manifest row, you have not parsed that region — go back to step 2.
Model the image in Office points by default.
960 pt as the long side unless the user requests a specific slide size.offset_x_pt / offset_y_pt; do not stretch the image independently on X and Y.scale = min(target_width_pt / image_width_px, target_height_pt / image_height_px)offset_x_pt = (target_width_pt - image_width_px * scale) / 2offset_y_pt = (target_height_pt - image_height_px * scale) / 2x_pt = offset_x_pt + x_px * scaley_pt = offset_y_pt + y_px * scalew_pt = w_px * scaleh_pt = h_px * scalex_pt = x_px * target_width_pt / image_width_pxy_pt = y_px * target_height_pt / image_height_pxw_pt = w_px * target_width_pt / image_width_pxh_pt = h_px * target_height_pt / image_height_pxscripts/coordinate_helper.py to calculate scale values and examples.Generate a complete runnable VBA macro, not a fragment. For the default presentation target, also save the macro as a .bas or .vba file in the working directory so it can be run or pasted without copying from chat.
Use a two-pass generation strategy. The two-pass split exists because layout errors are cheapest to catch before any styling is applied; do not skip Pass 1 to save time.
id printed inside as a label. No fills, no gradients, no shadows, no fonts beyond a default 10pt. The skeleton's only job is to confirm bbox positions, sizes, and arrow endpoints match the source. If the skeleton is visibly wrong, fix the manifest first, not the styling.Shapes.AddPicture.You may emit both passes as two separate Sub procedures inside the same .bas file (for example Sub BuildSkeleton() and Sub BuildFinal()), so the user can run the skeleton first and the styled version second without regenerating code.
The macro must include:
Sub ... End Sub wrapper.Shapes.AddPicture code for each preserved local crop in hybrid mode, with LinkToFile:=msoFalse and SaveWithDocument:=msoTrue where the host supports it.shp.Name = "Header_Background".RGB(...) or small helper functions.ZOrder or creation order.AITVBA_ for shape names and cleanup.Use Office APIs conservatively:
Shapes.AddShape, Shapes.AddTextbox, Shapes.AddLine, Shapes.BuildFreeform, FreeformBuilder.Shapes.AddPicture for preserved raster crops in hybrid mode.Fill.ForeColor.RGB, Fill.Transparency, Line.ForeColor.RGB, Line.Weight.TextFrame / TextFrame2 font settings as appropriate for the host.Shadow, GradientStops, PresetGradient, or layered translucent shapes to approximate effects.For the default presentation target, after generating the VBA:
.bas or .vba file.scripts/crop_preserved_elements.py when crop coordinates are known.scripts/vba_lint.py against the generated VBA file.scripts/detect_office_environment.py when possible.scripts/run_powerpoint_vba_windows.ps1.scripts/run_powerpoint_vba_macos.py when applicable..bas path, and give WPS-specific manual run steps.The final answer must not imply that a PNG preview is the editable deliverable. It must distinguish between source image, preview screenshot, VBA source file, editable deck file, WPS-compatible file, and any non-VBA PPTX fallback.
Perform these self-check rounds before final output:
Structure check: verify no major object, region, text block, connector, or layer is omitted; verify back-to-front order.
Editability check: verify that text, arrows, boxes, connectors, and other structural elements were recreated as editable Shapes unless explicitly placed in a preserved crop.
Preservation check: if hybrid mode is used, verify that every preserved raster element has a crop asset, asset path, AddPicture placement, shape name, and reason for preservation.
Code check: verify VBA syntax, variable declarations, object references, Office host APIs, cleanup logic, shape names, generated-file path, and preserved asset paths. Use scripts/vba_lint.py as a lightweight smoke check when code is available as a file or can be copied into a temporary file; do not overstate it as a full VBA compiler.
Materialization check: verify that the macro was saved, that preserved assets were saved when needed, that the available office runtime was detected, that the appropriate PowerPoint/WPS path was attempted, and that the output deck is open or a concrete blocker is reported.
Visual check (render-verify 强制闭环): 不允许停留在"人工目测"。这是保证还原度的关键环节,必须按下面步骤反复迭代直到达标或触发硬性上限。
每一轮的固定动作:
Slide.Export;macOS 用 AppleScript / PowerPoint 导出)。scripts/compare_images.py 与原图比对,输出整体 SSIM、整体像素差比例,以及差异最大的若干局部区域(按 bbox 列出)。通过条件(同时满足才能交付):
endpoints 字段对应的箭头在渲染图里目测连接到了正确的元素边界。迭代上限:最多 6 轮。每轮必须在最终报告里附一行"第 N 轮:SSIM=0.xx,最大差异区域=…,本轮修改了 …"。
终止策略:
报告语言:每轮的差异分析、区域定位、修改说明都用简体中文(遵循文件顶部 Output Language 规则)。
仅在本机确实无法跑宏时(无 Office、Trust Center 拦截、沙箱环境),才允许跳过该闭环并降级为标注清楚的"人工目测估计",且必须在报告中说明为什么没跑、用户在哪里能自行运行该闭环。
If a check finds a gap, revise the VBA before responding. Mention unresolved uncertainty only after revising what can be revised.
Use the structure in references/output-template.md:
Always include a short "How to run" section. Keep it host-specific and practical.
Do not promise perfect pixel-level reconstruction for complex photos, textures, real people, dense raster effects, or highly complex gradients. Explain that Office Shapes can approximate these but cannot fully reproduce raster detail.
Unless the user explicitly allows full-image insertion, do not place the original image on the slide/sheet/document and claim it is reconstructed. This restriction does not prohibit small local preserved crops in hybrid mode, as long as they are clearly labeled. If using a full background image is appropriate, label it clearly as the background-assisted option and keep editable overlays separate.
Never replace the editable deliverable with a PNG, screenshot, or generated raster image. A raster image may be used only for source analysis, validation, optional preview, or explicitly labeled local preserved elements in hybrid mode.
For "1:1" requests:
scripts/vba_lint.py: lightweight checks for generated VBA.scripts/detect_office_environment.py: detect likely Microsoft PowerPoint/WPS runtimes and recommend a materialization path.scripts/crop_preserved_elements.py: crop local preserved raster elements from the source image for hybrid reconstruction.scripts/run_powerpoint_vba_macos.py: attempt to run generated PowerPoint VBA through macOS PowerPoint automation and bring PowerPoint forward.scripts/run_powerpoint_vba_windows.ps1: attempt to import and run generated VBA through Windows Microsoft PowerPoint COM automation.scripts/compare_images.py: compare source image and rendered VBA screenshot.scripts/coordinate_helper.py: convert image pixels to Office point coordinates.references/vba-shape-patterns.md: common Office Shapes patterns.references/reconstruction-checklist.md: detailed review checklist.references/output-template.md: final response template.Published skills whose descriptions closely match this one, with their headline benchmark lift.
Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.