The kanban board has had full attachment storage and a dashboard HTTP API (upload/list/download/delete) since #35338, but there was no agent toolset tool and no `hermes kanban` CLI verb for attachments. Agents and scripts that don't go through the dashboard server (or can't touch the DB directly) had no way to create or read real attachments — only links in comments. Close that gap by mirroring the existing comment surface: - `kanban_db.store_attachment_bytes()` — one shared write path (validate name, enforce the 25 MB cap, write the blob under the per-task dir with collision-free naming, insert the metadata row, clean up an orphan blob if the insert fails). `_MAX_ATTACHMENT_BYTES`, `_safe_attachment_name`, and a new `_collision_free_path` move here so the dashboard, the tool, and the CLI all share one implementation and can't drift. - Tools (`tools/kanban_tools.py`): `kanban_attach` (inline base64), `kanban_attach_url` (server-side http/https fetch with the same cap), `kanban_attachments` (list). Write tools respect worker task-ownership; list is read-only. Registered in the `kanban` toolset. - CLI (`hermes_cli/kanban.py`): `attach <id> <path>`, `attachments <id>`, `attach-rm <attachment_id>`. - Dashboard `upload_task_attachment` now imports the shared helpers and uses `_collision_free_path` — behavior identical (still streams to disk with the cap, still 413 on overflow). - Docs (AGENTS.md, kanban-worker skill) and toolset membership updated. Tests: tool round-trip + oversize + bad base64 + ownership; attach_url against a local HTTP fixture incl. oversize-mid-stream and non-http scheme rejection; CLI attach/attachments/attach-rm; shared-helper unit tests; dashboard parity preserved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| dashboard_auth | ||
| proxy | ||
| subcommands | ||
| __init__.py | ||
| _parser.py | ||
| _subprocess_compat.py | ||
| active_sessions.py | ||
| auth.py | ||
| auth_commands.py | ||
| azure_detect.py | ||
| backup.py | ||
| banner.py | ||
| blueprint_cmd.py | ||
| browser_connect.py | ||
| build_info.py | ||
| bundles.py | ||
| callbacks.py | ||
| checkpoints.py | ||
| claw.py | ||
| cli_agent_setup_mixin.py | ||
| cli_commands_mixin.py | ||
| cli_output.py | ||
| clipboard.py | ||
| codex_models.py | ||
| codex_runtime_plugin_migration.py | ||
| codex_runtime_switch.py | ||
| colors.py | ||
| commands.py | ||
| completion.py | ||
| config.py | ||
| console_engine.py | ||
| container_boot.py | ||
| context_switch_guard.py | ||
| copilot_auth.py | ||
| cron.py | ||
| curator.py | ||
| curses_ui.py | ||
| dashboard_register.py | ||
| debug.py | ||
| default_soul.py | ||
| dep_ensure.py | ||
| diagnostics_upload.py | ||
| dingtalk_auth.py | ||
| doctor.py | ||
| dump.py | ||
| env_loader.py | ||
| fallback_cmd.py | ||
| fallback_config.py | ||
| gateway.py | ||
| gateway_enroll.py | ||
| gateway_windows.py | ||
| goals.py | ||
| gui_uninstall.py | ||
| hooks.py | ||
| input_sanitize.py | ||
| inventory.py | ||
| journey.py | ||
| kanban.py | ||
| kanban_db.py | ||
| kanban_decompose.py | ||
| kanban_diagnostics.py | ||
| kanban_specify.py | ||
| kanban_swarm.py | ||
| logs.py | ||
| main.py | ||
| managed_scope.py | ||
| managed_uv.py | ||
| mcp_catalog.py | ||
| mcp_config.py | ||
| mcp_picker.py | ||
| mcp_security.py | ||
| mcp_startup.py | ||
| memory_oauth.py | ||
| memory_providers.py | ||
| memory_setup.py | ||
| middleware.py | ||
| migrate.py | ||
| moa_cmd.py | ||
| moa_config.py | ||
| model_catalog.py | ||
| model_cost_guard.py | ||
| model_normalize.py | ||
| model_setup_flows.py | ||
| model_switch.py | ||
| models.py | ||
| nous_account.py | ||
| nous_auth_keepalive.py | ||
| nous_billing.py | ||
| nous_subscription.py | ||
| onepassword_secrets_cli.py | ||
| oneshot.py | ||
| pairing.py | ||
| partial_compress.py | ||
| pets.py | ||
| platforms.py | ||
| plugins.py | ||
| plugins_cmd.py | ||
| portal_cli.py | ||
| profile_describer.py | ||
| profile_distribution.py | ||
| profiles.py | ||
| projects_cmd.py | ||
| projects_db.py | ||
| prompt_size.py | ||
| provider_catalog.py | ||
| providers.py | ||
| psutil_android.py | ||
| pt_input_extras.py | ||
| pty_bridge.py | ||
| pty_session.py | ||
| relaunch.py | ||
| runtime_provider.py | ||
| secret_prompt.py | ||
| secrets_cli.py | ||
| security_advisories.py | ||
| security_audit.py | ||
| security_audit_startup.py | ||
| send_cmd.py | ||
| service_manager.py | ||
| session_export.py | ||
| session_export_html.py | ||
| session_export_md.py | ||
| session_filters.py | ||
| session_listing.py | ||
| session_recap.py | ||
| setup.py | ||
| setup_whatsapp_cloud.py | ||
| skills_config.py | ||
| skills_hub.py | ||
| skin_engine.py | ||
| slack_cli.py | ||
| sqlite_util.py | ||
| status.py | ||
| stdio.py | ||
| suggestions_cmd.py | ||
| telegram_managed_bot.py | ||
| timeouts.py | ||
| tips.py | ||
| tools_config.py | ||
| toolset_validation.py | ||
| uninstall.py | ||
| urllib_security.py | ||
| voice.py | ||
| web_git.py | ||
| web_server.py | ||
| webhook.py | ||
| win_pty_bridge.py | ||
| write_approval_commands.py | ||
| xai_retirement.py | ||