artifactkit
Installs as agent-artifact-kit, imports as artifactkit the PyPI name is descriptive
for discoverability, the import name is short because that's what you
actually type in code).
Generic artifact creation harness for agentic workflows. Agents build a declarative content spec; artifactkit renders it to docx/pptx/xlsx/pdf, writes it to a destination (local disk or S3), verifies the write, and returns the location. No agent workflow reimplements this on its own.
Install
pip install agent-artifact-kit[s3] # local + S3
pip install agent-artifact-kit[all] # + Strands and MCP adapters
All code below imports the package as artifactkit regardless of
which extras you installed.
Development
pip install -e ".[dev]"
pytest tests/ -v
pytest tests/ --cov=artifactkit --cov-report=term-missing # 93% with all extras installed (131 tests)
See PUBLISHING.md for how to build and release to PyPI, and
mkdocs.yml / docs/ for the full documentation site (pip install -e ".[docs]" then mkdocs serve).
Strands hooks
Beyond the tool functions, artifactkit.adapters.strands_hooks (under
the [strands] extra) provides three optional hook providers for a
Strands agent's lifecycle: policy enforcement (force a destination/theme
on every artifactkit call), a tracing bridge (correlate Strands'
invocation with artifactkit's operation_id in the logs), and
auto-delivery (deliver whatever a code-execution tool wrote, without
the agent having to remember to call deliver_files itself). See
docs/quickstart.md for usage — all three were verified against the
real strands-agents API (event mutability, shared invocation state,
result serialization), not assumed from documentation.
Observability
Every call is logged (structured, correlated by an operation_id
returned on the result) and, if you supply a MetricsSink, measured.
See docs/observability.md for the exact log events, fields, and
metric names, or wire in your own sink:
from artifactkit import ArtifactService, MetricsSink
class MySink:
def increment(self, name, tags=None): ...
def timing(self, name, duration_ms, tags=None): ...
service = ArtifactService(metrics=MySink())
Plain Python
from artifactkit import (
ArtifactService, ArtifactFormat, DocumentSpec, Heading, Paragraph,
destination_from_uri,
)
spec = DocumentSpec(
title="Q3 Summary",
blocks=(
Heading("Overview", level=1),
Paragraph.of("Revenue grew 12% quarter over quarter."),
),
base_filename="q3_summary", # optional — bare name, no extension
)
service = ArtifactService()
result = service.create(
spec,
ArtifactFormat.DOCX,
destination=destination_from_uri("s3://reports-bucket/q3"),
include_presigned_url=True,
# filename omitted: resolves to "q3_summary.docx" from spec.base_filename,
# adapted to whatever format is requested. Pass filename= explicitly to
# override it for this call without changing the spec.
)
print(result.location, result.presigned_url)
Strands agent
from strands import Agent
from artifactkit.adapters.strands_tools import create_docx, create_pptx, create_xlsx, create_pdf
agent = Agent(tools=[create_docx, create_pptx, create_xlsx, create_pdf])
MCP server
python -m artifactkit.adapters.mcp_server
Any MCP-capable agent can then call create_docx / create_pptx /
create_xlsx / create_pdf with a JSON spec, a destination_uri, and
a filename.
Spec shape
See artifactkit/core/parsing.py for the exact dict shape each tool
expects — it's the single source of truth both adapters parse against.
Styling
Bare output from python-docx/pptx/openpyxl looks exactly like what it
is: unstyled. Set theme on any structured spec for a named preset
(Theme.VIBRANT, Theme.CORPORATE, Theme.MINIMAL) that each backend
applies in whatever way fits its format — colored headings and an
accent rule in a doc, a gradient hero slide with a decorative shape in
a deck, a native Excel Table with banded rows and a colored tab in a
workbook. See docs/quickstart.md for examples of all three.
For a real branded .pptx, use template_path instead — inspect_template()
reads a template's layouts and placeholders first so you can target
them precisely ("idx:1" or an exact placeholder name), rather than
guessing at what a custom template contains. theme and template_path
don't combine: a template's own design wins.
Sheet.conditional_formats adds real Excel conditional formatting —
ColorScaleRule (heatmap), CellValueRule (highlight cells matching
a comparison), DataBarRule (in-cell proportional bars) — independent
of theme. See docs/quickstart.md.
Arbitrary files (code, images, anything else)
create() is for structured content that needs rendering (docx/pptx/xlsx/pdf).
For content you already have, code files, images, data files, whatever,
use create_files() instead. It skips rendering entirely and goes
straight to write + verify. If you hand it more than 5 files, it
bundles them into a single .zip automatically rather than doing one
write per file.
Each RawFile takes its content one of two ways:
from artifactkit import ArtifactService, RawFile, FileBundleSpec, destination_from_uri
# In-memory bytes (e.g. code the agent just wrote)
RawFile("main.py", content=b"print('hello')\n")
# A path already on disk (e.g. output from code that ran, a generated
# image, anything already written somewhere) -- read lazily at write
# time, never loaded into memory until it's actually needed.
RawFile("chart.png", source_path="/tmp/agent_run/chart.png")
If a piece of code produced a whole directory of output, skip
building RawFiles by hand:
bundle = FileBundleSpec.from_directory("/tmp/agent_run", bundle_filename="run_output")
service = ArtifactService()
result = service.create_files(bundle, destination_from_uri("s3://reports-bucket/runs"))
# 5 or fewer files in the directory -> delivered individually
# 6+ -> bundled into run_output.zip
Via Strands or MCP, this is the deliver_files tool. Each file entry
needs exactly one of content_base64 (for content the agent is
holding directly) or source_path (for content already on disk,
avoids hauling large payloads through the model's context just to
hand them back to this tool).
artifactkit never executes code or generates content. It only
delivers bytes that already exist. If app.py needs to run and
produce files, that execution happens entirely outside this library,
with whatever sandboxed runtime the agent already has, and
create_files() picks up only once the output exists on disk.
Design notes
- Render, validate, and write/verify are three separate stages. Only the write/verify stage retries; render and validate failures are deterministic and retrying wastes time.
ArtifactValidationError(bad spec/render) andArtifactWriteError(write couldn't be verified) are distinct exception types so a calling agent can choose the right remediation.- Destinations are pluggable via the
OutputDestinationprotocol. Adding GCS/Azure support means one new class, no changes to backends or the service. create()andcreate_files()share the same write/verify/retry/ presign machinery (ArtifactService._write_verified), the only difference is whether there's a render+validate step first. Arbitrary files skip it because there's no format-specific structure to check on content the caller already fully formed.
Metadata
Release files for agent-artifact-kit 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| agent_artifact_kit-0.3.0.tar.gz | 60.7 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_artifact_kit-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 109.7 kB
Release files / agent_artifact_kit-0.3.0.tar.gz
| Download URL | agent_artifact_kit-0.3.0.tar.gz |
|---|---|
| Size | 60.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
af60b12f2f7a8082c4c63a15282e2a50636dde15f3ef2071a354970a5f1e4ea9
|
|
BLAKE2b-256 checksum How to use checksums |
db04f3830286d000926cea6ad31f7263599936ea5035cf267f85c79ac55471f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logRelease files / agent_artifact_kit-0.3.0-py3-none-any.whl
| Download URL | agent_artifact_kit-0.3.0-py3-none-any.whl |
|---|---|
| Size | 49.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fe38dee68288fed4617295e765878523e0c0f6daa5f0dee0a0ffb267122e2041
|
|
BLAKE2b-256 checksum How to use checksums |
235f2fb1aabb4b9e33e4812634904273216e87ca7de302d91a63ed3e8b986dc6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logSecurity for agent-artifact-kit 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for agent_artifact_kit-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.