Changelog
All notable changes to this project are documented in this file. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
0.1.2 — 2025-07-18
Added
First-run bootstrap wizard: when no yoker configuration is found, the interactive bootstrap wizard runs so the user can configure a provider and model. The wizard writes
~/.yoker.tomlwithenabled = false— the user must then setenabled = trueand re-run. Non-interactive mode aborts with a message pointing to the docs. This matches the bootstrap flow in yoker-writing-assistant.
0.1.1 — 2025-07-18
Changed
Plugin configuration is now injected programmatically in
loop.pyat startup (config.plugins.enabled = True,yoker_assistantandpkgqadded toconfig.plugins.packages). Users no longer need to manually add a[plugins]section to their~/.yoker.toml— only backend config (provider, model, api_key) is required. Trust is confirmed by the user interactively on first run via yoker’s standard trust prompt; for permanent trust,[plugins.trusted]can optionally be added to~/.yoker.toml. This is the SDK equivalent of the--plugins-enabledCLI flag in yoker-writing-assistant.Updated all documentation to reflect the automatic plugin injection. External consumers using
yoker_assistant:md_to_htmlin their own projects still need manual[plugins]/[plugins.trusted]config.
Added
docs/folder with Sphinx + MyST +sphinx_rtd_themeconfiguration for ReadTheDocs (P4-001).docs/tutorial.md— the full build-story narrative (12 sections).docs/architecture.md,docs/security.md,docs/configuration.md,docs/api.md,docs/installation.md,docs/quickstart.md,docs/changelog.md,docs/index.md..readthedocs.yamlReadTheDocs build configuration.LICENSEfile (MIT)..env.examplereference template for email account configuration.AGENTS.md— project guide for code agents working on this codebase.PACKAGE.md— AI-optimized package documentation for consumers.README rewritten as the lean front-door with a Documentation section linking the full docs on ReadTheDocs.
0.1.0 — 2026-07-23
Added
P1-001 — uv Python project skeleton (
pyproject.toml,src/layout, console scriptyoker-assistant, standard Makefile targets).P1-002 — runtime dependencies (
yoker>=0.10.1,simple-email-gw>=0.3.0,pkgq>=0.3.2); local-path dev-wiring via[tool.uv.sources];yoker.toml.exampleand.env.examplereference templates.P1-003 — errata fixes: renamed
EMAIL_RECIPIENT_ADDRESSES→EMAIL_RECIPIENT_WHITELIST_ADDRESSESin.env.exampleandREADME.md;analysis/functional.mdcorrections (§2.2, §2.4, §4.3, §4.4). The originally-scopedMailboxwrapper class was descoped per owner feedback.P1-004 — agent construction + one-time session setup. The loop constructs yoker’s
Agentdirectly (noAssistantwrapper); the one-timeInitializeturn is inlined in the loop.P2-001 — ported the assistant agent definition to
src/yoker_assistant/agents/assistant.md; thetools:frontmatter was reworked to the bounded yoker set;pkgq:find(notfind_package) used as the plugin tool name.P2-008 — implemented the
md_to_htmltool as a yoker tool insrc/yoker_assistant/tools.py, exposed via__YOKER_MANIFEST__insrc/yoker_assistant/__init__.py. The conversion logic is vendored fromc3/bin/md-to-html.pyper owner instruction, with an HTML-escaping fix for XSS prevention.P2-009 — verified the dual-mode / external plugin load: a separate minimal yoker consumer loads
yoker-assistantas a plugin and callsyoker_assistant:md_to_html.P2-005 / P2-006 / P2-007 — the main loop, the handoff payload builder, and the reply sending with correct threading (combined implementation per owner directive). The loop polls IMAP for
UNSEEN, hands each email to the agent as the next user message in the persistent session, branches four ways on the reply, sends viasmtp.reply_emailwithhtml_body=andin_reply_to=, marks read, archives. Connect/ disconnect bookend each iteration.P3-001 — tests for the handoff contract (
tests/test_handoff.py): assertbuild_messageproduces the documented format (From/Subject/Datebody; NO
Instructions:block).
P3-002 — tests for the polling logic (
tests/test_loop.py): with fakeIMAPClient/SMTPClientstubs and a fakeAgent, assert the loop fetches unseen, callsprocess, sends viasmtp.reply_emailwithhtml_body=(notbody=, notsend_email), marks read, archives, in order; skips the send when the agent returns an empty reply body.S-01 —
SECURITY.mddocumenting the__YOKER_MANIFEST__change review process (blast-radius assessment, capability review, version pinning, review checklist).S-02 —
make pre-publishguard rejecting non-registry source URLs in built sdist/wheel metadata (file://, VCS schemes,@ <url>,path =); also rejects relative image paths inREADME.mdand verifiespyproject.tomlversion matches__init__.py__version__.
Decisions
Descoped
Mailboxwrapper (P1-003): wrapping two existing classes in a third class added no benefit for a demo/tutorial. The loop callsIMAPClient/SMTPClientdirectly.Descoped
Assistantwrapper (P1-004): same useless-wrapper pattern. The loop constructsAgentdirectly; the one-time setup is an inlinedawait agent.process(_INITIALIZE_PROMPT).Dropped
pa-session(P2-004): yoker’s persistent context manager carries session state natively acrossprocess()calls; no external state file needed.Reused
c3/bin/md-to-html.py(P2-008, owner instruction): did not reinvent the markdown-to-HTML converter; vendored the existing logic with an HTML-escaping fix.