zeno-tools-things
Things 3 / Things Cloud @tool wrappers for the Zeno AI assistant
framework, backed by things-sdk.
Three agent-callable tools:
things_list(when="today"|"inbox"|"anytime"|"someday")— read tasksthings_add(title, notes=None, when="inbox", deadline=None)— create a taskthings_complete(uuid)— mark a task complete
A ThingsAccount owns one local SQLite mirror plus one Things Cloud HTTP
client, with a TTL guard so a single conversational turn doesn't double-pull
from the cloud.
Install
uv add 'zeno-framework[things]'
Set credentials in the environment:
export THINGS_EMAIL="you@example.com"
export THINGS_PASSWORD="..."
Wiring
import asyncio
import contextlib
from pathlib import Path
from zeno.agent import Agent
from zeno.app import ZenoApp
from zeno.channels.cli import CliChannel
from zeno.memory import ThreeLayer
from zeno.memory.sqlite.conversation_store import SqliteConversationStore
from zeno.memory.sqlite.session_store import SqliteSessionStore
from zeno.memory.sqlite.user_memory_store import SqliteUserMemoryStore
from zeno.providers.claude_sdk import ClaudeSDKProvider
from zeno.tools_things import (
configure_things,
things_add,
things_complete,
things_list,
)
async def amain() -> None:
data = Path.home() / ".zeno"
data.mkdir(parents=True, exist_ok=True)
# Reads THINGS_EMAIL / THINGS_PASSWORD from the environment.
account = configure_things(
db_path=str(data / "things.db"),
sync_ttl_seconds=60,
)
agent = Agent(
name="root",
instructions="You manage the user's Things tasks.",
tools=[things_list, things_add, things_complete],
)
app = ZenoApp(
agent=agent,
memory=ThreeLayer(
session=SqliteSessionStore(data / "sessions.db"),
user_memory=SqliteUserMemoryStore(data / "user_memory.db"),
knowledge=..., # plug in zeno-chroma or zeno-qdrant
conversation=SqliteConversationStore(data / "conversations.db"),
),
channels=[CliChannel()],
provider=ClaudeSDKProvider(),
)
try:
await app.run()
finally:
with contextlib.suppress(Exception):
await account.stop()
asyncio.run(amain())
configure_things(...) installs a process-wide handle. Apps that prefer
per-Ctx wiring can set ctx.state["things"] = ThingsAccount(...)
directly — the tools resolve ctx.state first and fall back to the global.
Grouping the tools as a SubAgent
If your root agent has many responsibilities, isolate Things behind a specialist:
from zeno.agent import Agent, SubAgent
things_agent = SubAgent(
name="things",
instructions=(
"You manage the user's Things tasks. "
"Use `things_list` to read, `things_add` to create, "
"and `things_complete` to mark a task done."
),
tools=[things_list, things_add, things_complete],
)
root = Agent(
name="root",
instructions="Delegate todo-related questions to the `things` sub-agent.",
sub_agents=[things_agent],
)
Sub-agent dispatch works on ClaudeSDKProvider (Claude Agent SDK's Task
tool). OpenAIProvider does not support sub-agents — ZenoApp.start()
raises ProviderCapabilityError if you mix them.
Sync model
- Reads:
things_listcallspull_synconly if the last successful pull was outside the configured TTL (default 60 s). Back-to-back calls within the window reuse the cached SQLite state. - Writes:
things_addandthings_completewrite locally then callpush_syncimmediately so changes show up on every Things device right away.
License
MIT — see LICENSE.
Part of the Zeno framework.
Metadata
Release files for zeno-tools-things 1.1.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 | |
|---|---|---|---|
| zeno_tools_things-1.1.0.tar.gz | 12.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| zeno_tools_things-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.6 kB
Release files / zeno_tools_things-1.1.0.tar.gz
| Download URL | zeno_tools_things-1.1.0.tar.gz |
|---|---|
| Size | 12.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5059bd6a1b1eacaa265048c49116baa79d9896d36939f217df29fc914ebfcb13
|
|
BLAKE2b-256 checksum How to use checksums |
3d5e37a16b2dc35369b97bf43d0faae8bed0eefaa835cd3138d64ebca3250a42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 1, 2026.
Transparency logRelease files / zeno_tools_things-1.1.0-py3-none-any.whl
| Download URL | zeno_tools_things-1.1.0-py3-none-any.whl |
|---|---|
| Size | 10.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a3b4cec5cb9d1ba03ad0d97079da07642e1d1406cfc8532cfd7dc19078cdcee1
|
|
BLAKE2b-256 checksum How to use checksums |
85dd1e0499f31cb6551ac53982761d2cb11e0390961aac246f6a3bf127ce7ce3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 1, 2026.
Transparency log