Install any skill in seconds. Free to start, no credit card required.
Get Started Free →마크다운 원고를 진짜 책처럼 보이는 PDF·EPUB 전자책으로 만든다. 표지, 판권 페이지, 실제 쪽번호가 달린 목차, 장별 러닝헤더까지 갖춘다. Paged.js 사용.
SkillScore83/100
Test results 83
3/3 safety checks passed
46%83%of test cases passed +38 pts
Passed 20 of 24 test cases with the skill, and 11 of 24 without it.
10 fixed10 passed either way3 still failing1 broke
One test task스토어 이미지 텍스트 내 핵심 키워드에 형광펜 강조 효과를 주고자 합니다. 겟백 브랜드 규정에 맞춘 <span> 태그의 CSS background 및 box-shadow 설정은 무엇인가요?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add bam-bam-2-book-pdf
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("bam-bam-2-book-pdf")
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 bam-bam-2-book-pdfThe 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/bam-bam-2-book-pdf/SKILL.md https://app.decimal.ai/s/bam-bam-2-book-pdf/SKILL.md.claude/skills/bam-bam-2-book-pdf/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is 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 bam-bam-2-book-pdfimport 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdffrom 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdfimport 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdfimport 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdffrom 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdffrom 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdfimport 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdffrom 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdffrom 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add bam-bam-2-book-pdfimport 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add bam-bam-2-book-pdfimport 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add bam-bam-2-book-pdffrom 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("bam-bam-2-book-pdf")
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/bam-bam-2-book-pdf/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/bam-bam-2-book-pdf/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 1 other file is 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 bam-bam-2-book-pdfNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/bam-bam-2-book-pdf/SKILL.md https://app.decimal.ai/s/bam-bam-2-book-pdf/SKILL.md.agents/skills/bam-bam-2-book-pdf/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 1 other file is not included.
Raw files: /s/bam-bam-2-book-pdf/SKILL.md · /s/bam-bam-2-book-pdf.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/bam-bam-2-book-pdf/SKILL.mdcurl -fsSL https://app.decimal.ai/s/bam-bam-2-book-pdf.jsonThis gets SKILL.md only. The skill's 1 other file is 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.
일반 page.pdf() + 마크다운→HTML 변환만으로는 "리포트를 인쇄한 것"처럼 보인다.
실제 책이려면 최소 이 6가지가 있어야 한다: 표지(풀블리드) · 타이틀 페이지 · 판권 페이지 · 실제 쪽번호가 달린 목차 · 장 시작마다 새 페이지 · 쪽마다 러닝헤더/쪽번호.
이 스킬은 Paged.js(MIT, https://unpkg.com/pagedjs/dist/paged.polyfill.js)를 브라우저에 스크립트 태그로 로드해 CSS Paged Media 기능(러닝헤더, 목차 쪽번호 자동생성)을 구현한다. Chromium이 네이티브로 지원 안 하는 기능이라 이 폴리필이 필요하다.
page.pdf({width, height}) 파라미터가 무시된다. 항상 US Letter로 나온다. 반드시 preferCSSPageSize: true를 주고 CSS @page { size: 148mm 210mm; }로 크기를 지정할 것. format: 'A5' 같은 심볼릭 사이즈도 마찬가지로 무시되니 쓰지 말 것.page.setViewportSize()가 없다. 뷰포트 크기를 못 바꾸므로 표지 등 개별 이미지를 만들 때 page.screenshot({fullPage:true})로 큰 캔버스를 찍으면 타일링 버그가 난다. 대신 page.pdf() + pdftoppm으로 원하는 크기를 렌더링할 것.page.addScriptTag()가 없다. 외부 스크립트(Paged.js 등)는 document.write()로 쓰는 HTML 문자열 안에 <script src="https://unpkg.com/..."> 태그를 직접 넣어야 로드된다.@import/<link>가 document.write() 직후엔 타이밍 문제로 반영 안 될 때가 있다. 커스텀 세리프 폰트를 꼭 써야 하면 woff2를 직접 fetch해서 base64로 인라인 @font-face에 박아넣을 것. 급하면 시스템 폰트(-apple-system, 'Apple SD Gothic Neo')로 타협.target-counter()로 목차 쪽번호를 만들 때 한글 슬러그 id가 깨질 수 있다. pandoc이 자동 생성하는 id="1장-시작과-실패" 같은 한글 id 대신 ch-01, part-1, app-a 같은 ASCII id로 바꿔서 앵커를 걸 것.page: (named page) 속성을 제목 요소에만 주고 바로 다음 형제 요소에는 안 주면, 그 둘 사이에 강제 페이지베이크가 생긴다. 단순히 break-before: page로 장/부 시작만 제어하고 싶을 때는 page: main; 같은 명명 페이지 지정을 쓰지 말거나, 쓴다면 본문 전체에 동일하게 적용해야 한다 — 이건 "장 제목 바로 뒤에 이미지를 넣었는데 이미지가 다음 페이지로 밀리며 압도적인 빈 공백 페이지가 생기는" 증상으로 나타난다. 페이지 구성이 이상하면 가장 먼저 이 속성부터 의심할 것.document.querySelectorAll('.pagedjs_page').length가 N초 연속 안 바뀔 때까지 기다린 다음 page.pdf()를 호출할 것. 문서가 크면(80page.pdf()는 가로 flexbox를 통째로 날려버린다. display:flex로 카드 3장을 나란히 놓으면 화면(스크린샷)에서는 멀쩡한데 PDF 출력에서는 그 영역이 통째로 빈칸으로 나온다. 세로 방향(flex-direction:column)은 정상. <table>로 바꿔도 안 되니, 가로 배치가 필요하면 **display:inline-block + vertical-align:middle**로 짤 것. 이건 Paged.js와 무관하게 일반 page.pdf()에서도 발생한다.page.screenshot({clip})은 뷰포트(1440x900)를 넘는 영역을 못 찍는다. 세로 1600px짜리 썸네일을 clip으로 찍으면 900px 아래는 잘리고, 여러 번 찍으면 같은 이미지가 반복되거나 내용이 누락된다. setViewportSize()도 없으므로(함정 2), 큰 이미지는 무조건 page.pdf() + pdftoppm 경유로 만든다.document.write()를 반복 호출하면 이전 문서가 남아 중복 렌더링된다. 한 탭에서 여러 이미지를 연속으로 뽑을 때 결과물이 세로로 두 번 반복되거나 MD5가 전부 동일하게 나오면 이 증상이다. HTML을 파일로 쓰고 page.goto('file://<절대경로>')로 여는 방식이 안전하다 — file://은 이 환경에서 정상 동작하고, 매번 완전히 새 문서가 로드된다.document.write()로 넣은 스크립트에서 top-level const로 선언한 값이 나중 스크립트에서 안 보일 때가 있다. 렌더 함수를 window.render처럼 전역에 붙여도 데이터가 undefined로 잡히면, 스크립트를 쪼개지 말고 변형별로 완성된 HTML을 통째로 만들어 각각 파일로 저장할 것.pandoc manuscript.md -f markdown -t html5 --wrap=none -o body_raw.html. \newpage 같은 LaTeX 지시자는 HTML에서 무시되니 CSS break-before로 대체한다.h1/h2)에 ASCII id를 다시 부여하면서 장/부 디바이더 구조로 감싼다 (예: <h1> → <div class="part-divider" data-run="PART 1. ...">). 이때 원본 문서에 등장하는 순서를 한 번의 스캔으로 그대로 따라가는 배열을 만들어 목차 데이터로 쓴다 — h1 전체를 먼저 훑고 h2 전체를 나중에 훑는 식으로 두 번 나눠 처리하면 목차 순서가 깨진다(장이 전부 나온 뒤 부가 나오는 식).<a class="toc-entry" href="#ch-01">...</a> 형태로, CSS에서 .toc-entry::after { content: target-counter(attr(href url), page); }로 쪽번호를 자동 채운다.string-set: runninghead attr(data-run);, @page의 @top-center { content: string(runninghead); }로 받는다.@page cover { margin:0; } + page: cover;로 풀블리드, 그 외 프론트매터(타이틀/판권/목차)는 쪽번호·러닝헤더를 끈 @page front로 분리한다.const html = `<!DOCTYPE html><html><head>
<script src="https://unpkg.com/pagedjs/dist/paged.polyfill.js"></script>
<style>${css}</style></head><body>${frontMatter}${bodyContent}</body></html>`;
await page.evaluate((h) => { document.open(); document.write(h); document.close(); }, html);
// 안정화 폴링
let last = -1, stable = 0;
for (let i = 0; i < 60; i++) {
await sleep(1000);
const n = await page.evaluate(() => document.querySelectorAll('.pagedjs_page').length);
if (n === last) { if (++stable >= 3) break; } else stable = 0;
last = n;
}
const pdf = await page.pdf({ printBackground: true, preferCSSPageSize: true });
aside.pdf.renderPages()로 표지/타이틀/판권/목차/본문 몇 쪽을 실제로 렌더링해서 눈으로 확인한다. pdfinfo로 최종 Page size가 의도한 트림 사이즈(A5 등)인지 꼭 재확인한다 (함정 1번 재발 여부 체크).pandoc manuscript.md -t epub3 --css=epub.css --epub-cover-image=cover.jpg --toc --toc-depth=2 -o book.epub. EPUB은 리플로우 포맷이라 쪽번호/러닝헤더 개념이 없고 nav.xhtml 목차만 있으면 충분하다.표/인용문/코드블록이 문장 중간에서 맥려서 다음 페이지로 이어지는 건 CSS에 깨짐 방지 규칙이 없어서다. 다음을 기본값으로 넣을 것:
p { orphans: 3; widows: 3; }
table, blockquote, pre, img, figure { break-inside: avoid; page-break-inside: avoid; }
h2, h3 { break-after: avoid; page-break-after: avoid; } /* 소제목이 페이지 맨아래 혼자 남지 않게 */
이렇게 하면 문단/표/인용문이 한 페이지에 다 안 들어갈 때 그 블록 전체가 다음 페이지로 밀린다(사용자가 "앞 단락을 뒤로 밀어버려라"라고 표현하는 바로 그 동작). 부작용으로 강제 페이지보맜(장 시작 직전) 앞에 짧은 내용만 단독으로 낙은 거의-빈 페이지가 가끔 생기는데, 이건 실제 책에서도 흔한 자연스러운 현상이라 문제가 아니다. 적용 후반드시 처음부터 끝까지 순차적으로 모든 페이지를 렌더링해서 육안으로 확인할 것 — 하나만 집어서 보고 넘어가면 높은 확률로 놓친다.
제목+삽화를 한 덩어리로 묶어서 같은 페이지에 있게 하려고 display:flex를 쓨다면, Paged.js가 flex 컨테이너 내부 높이 계산을 제대로 못 해서 예상과 달리 자식 요소가 다음 페이지로 통째로 밀려나간다 (제목만 남고 삽화는 혼자 다음 장으로 가는 식). 한 페이지에 여러 요소를 묶을 때는 평범한 블록 흐름(margin/padding)만으로 레이아웃하고 flexbox/grid는 피할 것. 또한 제목과 그 바로 뒤에 오는 이미지 문단을 따로 처리하지 말고, 한 번의 정규식으로 단락(제목 헤딩 + 바로 뒤 이미지 단락)을 함께 매칭해서 하나의 div로 합쳐넣으면 둘이 한 덩어리로 취급되어 분리될 확률이 줄어든다.
색은 절제된 포인트 컬러 1개(골드/앰버 등)만 쓰고, 여백을 넉넉히 준다. 장 오프너는 "CH.01" 같은 뱃지 + 큰 제목, 인용구는 왼쪽 세로선 + 이탤릭으로 처리하면 무난하게 "책스럽다".
밤밤 이름으로 나가는 책·강의 상품이면 표지와 스토어 이미지를 겟백 브랜드 시스템으로 만든다. 임의로 예쁜 스타일을 지어내지 말 것.
~/Projects/getback/마케팅/insane-design/get100/design.md)작업 전에 위 문서를 먼저 읽고, 실제 홈페이지(get100.co.kr)도 한 번 열어본다.
#f5f5f0#0d0d0d, 라임 #D4F000, 퍼플 #7B2FFF 세 개만. 퍼플이 주인공, 라임이 강조Npx Npx 0 0 #0d0d0d(블러 0), 모서리 둥글림 0letter-spacing:-.03em~-.04em<span>에 background:#D4F000; box-shadow:0 0 0 5px #D4F000(형광펜 효과)확정된 형태: 썸네일 = 책 표지 그대로 + 하단 색 띠 하나, 커버 = 왼쪽 제목 + 오른쪽 구성 카드.
저장 규격과 실제 노출 규격이 다르다. 반드시 실제 크롭·표시 크기로 검증하고 올릴 것.
| 자리 | 업로드 규격 | 실제 노출 | 안전영역 |
|---|---|---|---|
| 커버 | 2100x900 (21:9) | 세로 중앙 382px만 보임 (5.49:1) | y 259~641 안에 모든 요소 |
| 썸네일 | 1200x1600 (3:4) | 목록에서 102x138px | 글자 최소 42px 이상(1200 기준) |
검증 명령:
magick cover.jpg -gravity center -crop 2100x382+0+0 +repage -resize 760x check_cover.jpg
magick thumb.jpg -resize 102x138! -resize 380% check_thumb.png
둘 다 눈으로 읽히는지 확인한 뒤 업로드한다.
// 1) 변형마다 완성된 HTML을 파일로 저장
const css = `<style>@page{size:1200px 1600px;margin:0}
.wrap{width:1200px;height:1600px;position:relative;overflow:hidden;background:#f5f5f0}
.row .ic{display:inline-block;vertical-align:middle} /* flex 금지 */
.row .k{display:inline-block;vertical-align:middle}
</style>`;
await fs.writeFile(tmp+'t_book.html', head+css+body+'</body></html>');
// 2) file://로 열고 PDF로 뽑는다 (screenshot 아님)
await page.goto('file://'+tmp+'t_book.html', {waitUntil:'load'});
await sleep(2400);
await fs.writeFile(tmp+'t_book.pdf',
await page.pdf({printBackground:true, preferCSSPageSize:true, pageRanges:'1'}));
# 3) PNG/JPG로 변환
pdftoppm -r 96 -png -singlefile t_book.pdf r_book
magick r_book.png -resize 1200x1600! -quality 93 thumb_book.jpg
서로 다른 변형인데 결과 MD5가 같으면 함정 11이 재발한 것이다. md5 -q로 매번 확인할 것.
상품 수정 화면의 input[type=file] 순서가 고정이다.
| nth | 용도 | accept |
|---|---|---|
| 0 | 본문 삽입 이미지 | image/* |
| 1 | 커버(21:9) | image/* |
| 2 | 썸네일(3:4) | image/* |
| 3 | 첨부 파일 | .pdf,.zip,.epub |
// 내 크리에이터 프로필 → 프리미엄 탭 → 수정하기(목록은 최신순)
await page.locator('input[type=file]').nth(1).setInputFiles(tmp+'cover.jpg'); await sleep(4500);
await page.locator('input[type=file]').nth(2).setInputFiles(tmp+'thumb.jpg'); await sleep(4500);
// 저장 버튼 클릭
주의할 점
input[type=file]을 다시 쓰면 교체가 아니라 추가된다. 그래서 같은 PDF가 여러 장 쌓이기 쉽다. 다만 본문의 "첨부 삭제" 버튼은 정상 동작한다 — 카드를 지우고 「저장」하면 반영된다 (2026-09-12 실측: 중복 3장 → 1장 정리 성공).?t=<timestamp>)을 붙이거나 page.reload()로 강제 새로고침한 뒤에 판단할 것. 본문 innerText 기반 개수 세기도 하이드레이션 중에는 중복해서 나오니 충분히 기다렸다 재셑할 것.page.reload() → 의도한 변경이 화면에 보이는지 확인 → 그다음에 손댈 것.iframe[src*="youtube"] 개수와 첨부 카드 개수를 세어볼 것.img를 가진 자식 노드를 찾아 setStartBefore/setEndAfter로 하나씩 선택 후 Delete를 반복할 것.node-paywallBlock)를 기준으로 무료 공개 비율이 자동 계산된다. 편집 후 여기부터 유료 / 공개 N% 문구로 확인Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.