{ "body": "\n\nTeam-lead source issue: #2\nParent architecture issue: #1\n\n## Developer Task\n\nComplete the native-process CLI, JSON request handling, status vocabulary and exit codes\n\n## Scope\n\nFinish tools/example.py as the plain `python -m tools.example [REQUEST.json | flags]` CLI: parse topic, desired width and height, format (png|ico), source, --count, --download, --output-dir, --resize and --dry-run, or load the same fields from a JSON request document; emit exactly one machine-readable JSON document on stdout containing the used source, the item list and a fixed status vocabulary with matching exit codes (ok=0, dry_run=0, invalid_request=2, no_format=3, no_size=4, access_error=5, partial_download=6). Unsupported formats and an unknown --source produce invalid_request carrying the accepted values and the available source ids. Add tools/envelope.py with the status/exit-code table and response builder, extend tools/errors.py with request errors, keep --help documenting every parameter, and rewrite examples/input.json as the canonical dry_run request example so the facade smoke command stays green and offline.\n\n## Acceptance Criteria\n\n- Affected file `tools/envelope.py` is `valid`.\n- Test artifact `tests/test_cli.py` `passes` through the standard test entrypoint.\n- Facade command `tools.validate` `succeeds`.\n- Facade command `tools.test` `succeeds`.\n- Facade command `tools.smoke` `succeeds`.\n- Facade acceptance check `help-command` `passes`.\n- Capability `public_cli` is `provided` by evidence `cli-contract-tested`, `facade-validate-succeeds`, `facade-test-succeeds`, `facade-smoke-succeeds`, `facade-help-command-passes`.\n\n## Test Hints\n\n- pytest tests/test_cli.py through the tools.test entrypoint; assert one JSON document on stdout, the status/exit-code table for every branch reachable without network, unknown source listing available ids, unsupported format rejection and --help output.\n- python -m tools.example --help\n- python -m tools.example examples/input.json\n- python -m compileall tools tests\n- tests/test_cli.py\n- tools/envelope.py\n- Add or update focused tests for the changed behavior.\n- Ensure those tests run through the repository's standard CI test entrypoint; a local-only test run is not sufficient.\n- Verification mechanisms declare their executor, phase, prerequisites and evidence format in verification_execution. Task acceptance and final product acceptance are separate phases; service code does not imply an additional artifact publication stage.\n\n## Requirement References\n\n- R1: `REQ-001` REQ-001 Утилита является консольным приложением, запускаемым как обычный исполняемый процесс; параметры запуска задают тему поиска, желаемый размер, формат, источник, флаг скачивания и флаг масштабирования.\n- R2: `REQ-002` REQ-002 Результат работы выводится в машиночитаемом структурированном виде, пригодном для tool calling ИИ-агентом: перечень найденных изображений с источником, URL, форматом и фактическими размерами, а также однозначное различие между успехом, отсутствием подходящих изображений и ошибкой.\n- R4: `REQ-004` REQ-004 Источник изображений выбирается вызывающей стороной через параметр; схема допускает подключение нескольких источников, и в поставку входит как минимум один рабочий бесплатный источник; неизвестный источник даёт явную ошибку с перечнем доступных источников.\n\n## Affected Repos / Files\n\n- tools/example.py\n- tools/envelope.py\n- tools/errors.py\n- examples/input.json\n- tests/test_cli.py\n\n## Required Outputs\n\nThese outputs are absent facade prerequisites assigned to this task by `affected_files`; their intents are declarations from the accepted plan.\n\n- `tools/example.py`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`tools`, `tools/example.py`, required_by=`tools.smoke`, `tools.validate`\n- `tools/envelope.py`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`tools`, required_by=`tools.validate`\n- `tools/errors.py`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`tools`, required_by=`tools.validate`\n- `examples/input.json`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`examples/input.json`, required_by=`tools.smoke`\n- `tests/test_cli.py`: state=`absent_at_planning`, intent=`modify_final`, satisfies=`tests`, required_by=`tools.validate`\n\n## Facade Slice Contract\n\nThe facade is the global CI contract for the whole task branch. This task may implement only a slice, but it must not contradict the facade layout or modify protected facade/control paths.\n\n- Task kind: `public_interface`\n- Facade path: `.agent/project.yaml` (`initialized`)\n- Required facade paths: `examples/input.json`, `tests`, `tests/test_example.py`, `tools`, `tools/example.py`\n- Support facade paths: `.env.example`, `pyproject.toml`, `uv.lock`\n- Facade commands: tools.dependencies.restore: `/opt/agent-environment/bin/python -I -m agent_environment_executor.cli --workspace \"$PWD\" --component 'tools' --mode restore`, tools.validate: `python -m compileall tools tests`, tools.test: `pytest`, tools.smoke: `python -m tools.example examples/input.json`\n- Facade acceptance: import-package (package_import), help-command (cli_command)\n- Protected paths: `.agent/acceptance.yaml`, `.agent/project.yaml`, `.gitea/workflows/`\n\n## File Intents\n\n- `tools/example.py`: `modify_final`, ownership_scope=`exact_path`\n- `tools/envelope.py`: `modify_final`, ownership_scope=`exact_path`\n- `tools/errors.py`: `modify_final`, ownership_scope=`exact_path`\n- `examples/input.json`: `modify_final`, ownership_scope=`exact_path`\n- `tests/test_cli.py`: `modify_final`, ownership_scope=`exact_path`\n\n## Acceptance Checks\n\n- `cli-envelope-module-valid` `artifact_state` `affected_file:tools/envelope.py` expected=`valid`\n- `cli-contract-tested` `test_result` `affected_file:tests/test_cli.py` expected=`passes`\n- `facade-validate-succeeds` `facade_command_result` `facade_command:tools.validate` expected=`succeeds`\n- `facade-test-succeeds` `facade_command_result` `facade_command:tools.test` expected=`succeeds`\n- `facade-smoke-succeeds` `facade_command_result` `facade_command:tools.smoke` expected=`succeeds`\n- `facade-help-command-passes` `facade_acceptance_result` `facade_acceptance:help-command` expected=`passes`\n- `public-cli-provided` `capability_result` `capability:public_cli` expected=`provided` evidence=cli-contract-tested,facade-validate-succeeds,facade-test-succeeds,facade-smoke-succeeds,facade-help-command-passes\n\n## Facade Refs\n\n- Commands: `tools.validate`, `tools.test`, `tools.smoke`\n- Paths: _none_\n\n- Acceptance: `help-command`\n\n## Capability Contract\n\n- Provides: `public_cli` (`public_interface`)\n- Requires: `source_registry` (`external_integration`), `toolkit_layout` (`structure`)\n\n## Integration Contract\n\n- Functional dependencies: [2]\n- Execution predecessors: [1, 2]\n- Integrate the current target before checks; preserve active product obligations from accepted tasks.\n- Task-local criteria are not inherited. Product changes require explicit add/revise/retire declarations; revisions and retirements require approved authority.\n- Requirement changes: `[]`\n\n## Dependencies\n\n- Child task #3\n- Child task #4\n- Call out any dependency that blocks implementation.\n\n## Risk Notes\n\n- Preserve existing public behavior unless explicitly requested.\n- UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes.\n- UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed.\n- UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior.\n- UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized.\n- UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics.\n- Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback.\n- Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results.\n- Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades.\n\n## Parent Links\n\n- Team-lead issue: #2\n- Parent architecture issue: #1\n\n## Architecture / Lead Context\n\nThe context below describes the whole product. Scope and Acceptance Criteria define local completion; the Integration Contract additionally requires preservation of active product obligations.\n\n# Team lead handoff\n\n\n\nParent architecture issue: #1\n\nSource title: Консольная утилита поиска и скачивания изображений для вызова ИИ-агентом\n\nContract asset: `agent-architecture-handoff.v1.json`\n\nContract SHA-256: `2556d39044bc87f828704b28f39f1b136761f18330c69c087a387f1ae69fa2bf`\n\n## Workflow\n- Repository: projects/product-54354138-1\n- Repository intent: existing_repository\n- Base branch: `master`\n- Target branch: `task/1-task`\n- Facade: `.agent/project.yaml` (`initialized`)\n- CI: `created`\n- Created repository: `false`\n- Created branch: `true`\n- Facade template: `script_toolkit_python`\n- Facade action: `initialize`\n- Project shape: `project_kind=script_toolkit, languages=['python'], runtimes=['command_line'], interfaces=['cli'], delivery_kind=native_process`\n- Project shape requirement refs: `project_kind=['REQ-001', 'REQ-011'], languages=['REQ-001', 'REQ-011'], runtimes=['REQ-001', 'REQ-011'], interfaces=['REQ-001', 'REQ-002', 'REQ-009'], delivery_kind=['REQ-011']`\n- Facade placement: `kind=repository_root`\n\n\n\n\n\n## Architecture Plan\n\n### Context\nProduct request issue #1: a console (CLI) image search/download utility invoked by an AI agent via tool calling. Contract requirements REQ-001..REQ-011: parameters for topic, desired size, format (initial set png/ico), source, download flag and resize flag; machine-readable structured output distinguishing success / no-images-of-format / no-images-of-size / source-access error (AC-001, AC-011); free access without API keys or secrets (REQ-003, AC-002); pluggable source selection with explicit unknown-source error listing available sources (REQ-004, AC-003); only requested format returned and explicit \"no images of this format\" message distinct from access errors (REQ-007, AC-004); only images not smaller than the desired size in both dimensions, with actual dimensions reported (REQ-006, REQ-008, AC-005, AC-006); download into a caller-specified directory with reported paths (REQ-009, AC-007); downscale-only resizing behind a flag, unchanged dimensions without the flag (REQ-010, AC-008); live-source verification on a known topic (AC-010); delivered and run as a plain executable process with no Docker/containers (REQ-011, AC-009). Approved network access is Wikimedia Commons and Open\n\n### Decision\nShape: script_toolkit (Python 3, command_line runtime, cli interface, native_process delivery, repository_root placement). This is the narrowest catalog-template-backed shape that covers every resulting language, runtime, public interface and delivery form: the deliverable is one command-line program that speaks over argv/stdout, there is no HTTP server and no second language, and REQ-011/AC-009 forbid container delivery. 'file_io' is intentionally not declared as a separate public interface: writing downloaded files into the caller-specified directory (REQ-009) and reporting the resulting paths (REQ-002) is internal behavior of the CLI invocation, not an independent repository interface, and declaring it would leave the shape without a supported facade template. Facade: initialize (currently missing) at repository_root, since no product artifact fixes a component root. Implementation direction: a single Python CLI entry module parsed with argparse (topic, desired width/height, format png|ico, source, --count limit, --download, --output-dir, --resize), a small source-adapter registry (Wikimedia Commons MediaWiki API first, Openverse as a second adapter behind the same registry) so \n\n### Constraints\n- Project shape is limited to script_toolkit/Python/command_line/cli/native_process at repository_root; do not add an HTTP service, a second language or container packaging.\n- Delivery must be a plain executable process (REQ-011, AC-009): no Dockerfile, compose file or container entrypoint.\n- Only free, credential-free sources; no API keys, tokens, registration or secret configuration may be required or read at runtime (REQ-003, OOS-003).\n- Only Wikimedia Commons and Openverse over HTTPS 443 (incl. subdomains) are approved network destinations; no other hosts and no public-download fallbacks.\n- Format support limited to png and ico (REQ-007, OOS-002); no other formats and no editing beyond downscaling (OOS-001).\n- Output must remain a single machine-readable JSON document with distinct status values and matching exit codes for success, no-format, no-size, access error and invalid request (REQ-002, AC-001, AC-011).\n- Filters must be applied on the client side to the actual downloaded/parsed image data, not trusted from source metadata alone, so reported format and dimensions are real.\n- Resizing may only downscale to the desired size and must be off by default (REQ-010, AC-008).\n\n### Risks\n- UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes.\n- UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed.\n- UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior.\n- UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized.\n- UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics.\n- Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback.\n- Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results.\n- Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades.\n\n### Team Lead Handoff\n- First prove the smallest end-to-end public path on the live source: run the CLI for a known topic against Wikimedia Commons requesting png, observe a non-empty JSON list with working URLs and real dimensions (AC-010), then confirm the same run with no API key/credential env vars set (AC-002).\n- Bounded check for UNK-001: issue one documented MediaWiki/Openverse search request and record whether size/mime filtering is available server-side and how many candidates must be fetched to satisfy the >= size rule; the decision between server-side parameters and client-side-only filtering (and any candidate cap) depends on that observation.\n- Bounded check for UNK-003: run a handful of sequential requests and record response codes, any 429 behaviour and whether a custom User-Agent is required; the retry/backoff design and whether a --count cap is enforced client-side depend on the result.\n- Bounded check for UNK-002: query an ico request against the chosen source and record whether the no-format status is produced while the source is reachable; this decides how the no-format message is worded and which exit code is paired with it.\n- Bounded check for Pillow availability: attempt prepare_environment with the declared manifest and record whether Pillow resolves from the internal catalog; the choice between Pillow-based ICO decode/resize and a reduced, explicitly recorded capability depends on that result. If it is missing, request operator publication; do not add public index fallbacks or credential changes.\n- Decide and document UNK-004 and UNK-005 with the product owner before finalizing REQ-009 output: default download directory behaviour and the status/exit code for partial download success.\n- All dependency changes must go through the manifests and lock files declared by the generated facade and Tool Backend prepare_environment; agents must not change package sources, credentials, network access or admission policy, and any policy exception requires human approval.\n- Preserve required coverage: every status branch (success, no-format, no-size, access error, invalid/unknown source) needs its own executed check and matching exit code, and aggregate exit 0 must not be treated as proof that the no-format and no-size outcomes work.\n\n# Parent architecture issue\n\n\n\n## Summary\nНужно консольное приложение (CLI), запускаемое как обычный исполняемый процесс, которое по заданной теме находит изображения в бесплатных источниках и по флагу скачивает их. Инструмент предназначен для вызова ИИ-агентом через tool calling, поэтому результат должен быть машиночитаемым и однозначно различать успех, отсутствие подходящих изображений и ошибку. Доступ бесплатный, без API-ключей и регистрации. Источник не принципиален, но выбирается вызывающей стороной, схема допускает несколько подключаемых источников, и в поставку входит как минимум один рабочий бесплатный источник. Задаются тема, желаемый размер и формат из начального набора png/ico. Возвращаются только изображения запрошенного формата, не меньшие желаемого размера; если таких форматов нет — явное сообщение, что изображений такого формата нет; если подходящих по размеру нет — явное сообщение, что подходящих по размеру нет. При наличии флага масштабирования изображения больше желаемого размера уменьшаются до желаемого. Запуск — как обычный процесс, без Docker. Сетевой доступ к бесплатным источникам согласован пользователем вне этого обсуждения (Wikimedia Commons и Openverse, HTTPS 443, включая поддомены).\n\n## Requirements\n- `REQ-001` REQ-001 Утилита является консольным приложением, запускаемым как обычный исполняемый процесс; параметры запуска задают тему поиска, желаемый размер, формат, источник, флаг скачивания и флаг масштабирования.\n- `REQ-002` REQ-002 Результат работы выводится в машиночитаемом структурированном виде, пригодном для tool calling ИИ-агентом: перечень найденных изображений с источником, URL, форматом и фактическими размерами, а также однозначное различие между успехом, отсутствием подходящих изображений и ошибкой.\n- `REQ-003` REQ-003 Доступ к источникам бесплатный, без API-ключей, регистрации и иных учётных данных; поиск выполняется без настройки секретов.\n- `REQ-004` REQ-004 Источник изображений выбирается вызывающей стороной через параметр; схема допускает подключение нескольких источников, и в поставку входит как минимум один рабочий бесплатный источник; неизвестный источник даёт явную ошибку с перечнем доступных источников.\n- `REQ-005` REQ-005 Поиск выполняется по теме (текстовому запросу), задаваемой вызывающей стороной; количество возвращаемых результатов может быть ограничено вызывающей стороной.\n- `REQ-006` REQ-006 Вызывающая сторона задаёт желаемый размер изображения (ширина/высота); в результатах по каждому изображению указываются его фактические размеры.\n- `REQ-007` REQ-007 Формат изображения выбирается из начального набора png и ico; возвращаются только файлы запрошенного формата, а при отсутствии таких изображений у источника выдаётся явное сообщение, что изображений такого формата нет, отличимое от ошибки доступа к источнику.\n- `REQ-008` REQ-008 Возвращаются только изображения, размер которых не меньше желаемого по обоим измерениям; если у источника по теме нет изображений подходящего размера, выдаётся явное сообщение, что подходящих по размеру нет, отличимое от сообщения об отсутствии формата и от ошибки доступа.\n- `REQ-009` REQ-009 По флагу скачивания найденные изображения сохраняются в каталог, указанный вызывающей стороной, а в результате сообщаются пути сохранённых файлов.\n- `REQ-010` REQ-010 При наличии флага масштабирования изображения, доступные только в размере больше желаемого, уменьшаются до желаемого размера; без этого флага изображения сохраняются без изменения размеров.\n- `REQ-011` REQ-011 Утилита поставляется и запускается как обычный исполняемый процесс, без Docker и контейнеров.\n\n## Artifacts\n_None recorded._\n\n## Delivery Requirements\n- `native_process` (requirements=['REQ-011'])\n\n## External Inputs\n_None recorded._\n\n## Acceptance Criteria\n- `AC-001` AC-001 Для заданной темы утилита возвращает машиночитаемый список результатов, в каждом элементе есть URL, формат и фактические размеры; успешный поиск, отсутствие подходящих изображений и сбой различимы по коду завершения и структуре вывода.\n- `AC-002` AC-002 Поиск успешно выполняется в окружении, где не задано ни одного API-ключа или учётных данных.\n- `AC-003` AC-003 Указание источника в параметрах приводит к использованию соответствующего источника, и использованный источник явно отражён в выводе; неизвестный источник даёт явную ошибку с перечнем доступных источников.\n- `AC-004` AC-004 Запрос формата png возвращает только реальные png-файлы; запрос ico при отсутствии ico у источника даёт явное сообщение о том, что изображений такого формата нет, и это сообщение отличимо от сообщения об ошибке доступа к источнику.\n- `AC-005` AC-005 При запросе желаемого размера в выдаче присутствуют только изображения, размер которых не меньше желаемого по обоим измерениям, и для каждого указаны фактические размеры.\n- `AC-006` AC-006 Если по теме у источника есть только изображения меньше желаемого размера, вывод содержит явное сообщение, что подходящих по размеру нет, и это сообщение отличимо от сообщения об отсутствии формата и от ошибки доступа.\n- `AC-007` AC-007 При указании флага скачивания файлы физически сохранены в заданном каталоге, пути в выводе соответствуют существующим файлам, и файлы открываются как изображения заявленного формата.\n- `AC-008` AC-008 При наличии флага масштабирования изображение, найденное в размере больше желаемого, сохраняется с размерами, равными желаемым; без этого флага фактические размеры сохранённого файла совпадают с исходными.\n- `AC-009` AC-009 Утилита запускается как обычный исполняемый процесс без Docker и без контейнерной обвязки.\n- `AC-010` AC-010 Реальная проверка на известном результате: запрос по теме, для которой у выбранного источника заведомо есть изображения, возвращает непустой список с рабочими ссылками на файлы (проверка на живом источнике, а не только на синтетических данных).\n- `AC-011` AC-011 При запрещённом сетевом доступе к источнику утилита завершается явной ошибкой доступа и не выдаёт результат, выглядящий как успешный поиск.\n\n## Out of Scope\n- `OOS-001` Генерация изображений и любые операции редактирования, кроме уменьшения до желаемого размера\n- `OOS-002` Форматы изображений вне начального набора png/ico\n- `OOS-003` Платные и требующие API-ключей источники изображений\n- `OOS-004` Запуск в Docker/контейнерах\n- `OOS-005` Графический интерфейс пользователя\n\n## Unknowns / Risks\n- `UNK-001` Какой именно бесплатный источник реализуется первым и покрывает ли его API фильтрацию по размеру/формату или фильтрация выполняется на стороне клиента (влияет на объём загружаемых данных)\n- `UNK-002` Практическая доступность файлов формата ico у бесплатных источников: ожидаемо такие запросы будут часто возвращать сообщение об отсутствии формата\n- `UNK-003` Ограничения частоты запросов и требования к идентификации клиента (user agent) у выбранного бесплатного источника\n- `UNK-004` Каталог сохранения по умолчанию, если вызывающая сторона не задала его явно\n- `UNK-005` Как сообщать частичный успех скачивания, когда часть файлов сохранилась, а часть нет\n\n## Workflow\n- Readiness: `ready_for_architecture`\n- Contract asset: `agent-product-contract.v1.json`\n- Contract SHA-256: `b7622222e96d133d4c82b5d716cb2963e8b786272d2735fe9033295141b75ba6`\n- Transcript: `https://git.p2prod.ru/platform/product-requests/issues/1`\n- Generated by: `product-manager-agent`\n\n# Architect plan comments\n\n\n## Architecture Plan\n\n### Context\nProduct request issue #1: a console (CLI) image search/download utility invoked by an AI agent via tool calling. Contract requirements REQ-001..REQ-011: parameters for topic, desired size, format (initial set png/ico), source, download flag and resize flag; machine-readable structured output distinguishing success / no-images-of-format / no-images-of-size / source-access error (AC-001, AC-011); free access without API keys or secrets (REQ-003, AC-002); pluggable source selection with explicit unknown-source error listing available sources (REQ-004, AC-003); only requested format returned and explicit \"no images of this format\" message distinct from access errors (REQ-007, AC-004); only images not smaller than the desired size in both dimensions, with actual dimensions reported (REQ-006, REQ-008, AC-005, AC-006); download into a caller-specified directory with reported paths (REQ-009, AC-007); downscale-only resizing behind a flag, unchanged dimensions without the flag (REQ-010, AC-008); live-source verification on a known topic (AC-010); delivered and run as a plain executable process with no Docker/containers (REQ-011, AC-009). Approved network access is Wikimedia Commons and Open\n\n### Decision\nShape: script_toolkit (Python 3, command_line runtime, cli interface, native_process delivery, repository_root placement). This is the narrowest catalog-template-backed shape that covers every resulting language, runtime, public interface and delivery form: the deliverable is one command-line program that speaks over argv/stdout, there is no HTTP server and no second language, and REQ-011/AC-009 forbid container delivery. 'file_io' is intentionally not declared as a separate public interface: writing downloaded files into the caller-specified directory (REQ-009) and reporting the resulting paths (REQ-002) is internal behavior of the CLI invocation, not an independent repository interface, and declaring it would leave the shape without a supported facade template. Facade: initialize (currently missing) at repository_root, since no product artifact fixes a component root. Implementation direction: a single Python CLI entry module parsed with argparse (topic, desired width/height, format png|ico, source, --count limit, --download, --output-dir, --resize), a small source-adapter registry (Wikimedia Commons MediaWiki API first, Openverse as a second adapter behind the same registry) so \n\n### Constraints\n- Project shape is limited to script_toolkit/Python/command_line/cli/native_process at repository_root; do not add an HTTP service, a second language or container packaging.\n- Delivery must be a plain executable process (REQ-011, AC-009): no Dockerfile, compose file or container entrypoint.\n- Only free, credential-free sources; no API keys, tokens, registration or secret configuration may be required or read at runtime (REQ-003, OOS-003).\n- Only Wikimedia Commons and Openverse over HTTPS 443 (incl. subdomains) are approved network destinations; no other hosts and no public-download fallbacks.\n- Format support limited to png and ico (REQ-007, OOS-002); no other formats and no editing beyond downscaling (OOS-001).\n- Output must remain a single machine-readable JSON document with distinct status values and matching exit codes for success, no-format, no-size, access error and invalid request (REQ-002, AC-001, AC-011).\n- Filters must be applied on the client side to the actual downloaded/parsed image data, not trusted from source metadata alone, so reported format and dimensions are real.\n- Resizing may only downscale to the desired size and must be off by default (REQ-010, AC-008).\n\n### Risks\n- UNK-001: it is unverified whether the chosen first source supports server-side filtering by size/format; if not, client-side filtering against REQ-008 may require downloading many candidates and could hit timeouts or rate limits, affecting REQ-007 and REQ-008 outcomes.\n- UNK-002: ico availability on free sources is unknown; the no-format path (REQ-007) may be the common outcome and must be proven to be distinct from access errors rather than assumed.\n- UNK-003: source rate limits and User-Agent/identification requirements are unverified and could turn normal usage into access errors, affecting REQ-003 and AC-011 behavior.\n- UNK-004: the default download directory when the caller omits it is an open product decision; either a mandatory --output-dir error or a documented default must be confirmed before REQ-009 is finalized.\n- UNK-005: partial download success reporting is an open product decision affecting REQ-009 and REQ-002 status semantics.\n- Pillow (or an equivalent decoder/resizer) availability in the internal Gitea catalog is unverified; if it is not published, ICO dimension verification and downscaling (REQ-007, REQ-010) cannot be satisfied with stdlib alone and must not be replaced by a public-download fallback.\n- Live-source reachability for AC-010 depends on runtime egress to the approved hosts; if the sandbox cannot reach them, that limitation must be recorded instead of substituting synthetic results.\n- Exit-code and status vocabulary must be fixed once and reused by all branches, otherwise AC-001/AC-006 distinguishability degrades.\n\n### Team Lead Handoff\n- First prove the smallest end-to-end public path on the live source: run the CLI for a known topic against Wikimedia Commons requesting png, observe a non-empty JSON list with working URLs and real dimensions (AC-010), then confirm the same run with no API key/credential env vars set (AC-002).\n- Bounded check for UNK-001: issue one documented MediaWiki/Openverse search request and record whether size/mime filtering is available server-side and how many candidates must be fetched to satisfy the >= size rule; the decision between server-side parameters and client-side-only filtering (and any candidate cap) depends on that observation.\n- Bounded check for UNK-003: run a handful of sequential requests and record response codes, any 429 behaviour and whether a custom User-Agent is required; the retry/backoff design and whether a --count cap is enforced client-side depend on the result.\n- Bounded check for UNK-002: query an ico request against the chosen source and record whether the no-format status is produced while the source is reachable; this decides how the no-format message is worded and which exit code is paired with it.\n- Bounded check for Pillow availability: attempt prepare_environment with the declared manifest and record whether Pillow resolves from the internal catalog; the choice between Pillow-based ICO decode/resize and a reduced, explicitly recorded capability depends on that result. If it is missing, request operator publication; do not add public index fallbacks or credential changes.\n- Decide and document UNK-004 and UNK-005 with the product owner before finalizing REQ-009 output: default download directory behaviour and the status/exit code for partial download success.\n- All dependency changes must go through the manifests and lock files declared by the generated facade and Tool Backend prepare_environment; agents must not change package sources, credentials, network access or admission policy, and any policy exception requires human approval.\n- Preserve required coverage: every status branch (success, no-format, no-size, access error, invalid/unknown source) needs its own executed check and matching exit code, and aggregate exit 0 must not be treated as proof that the no-format and no-size outcomes work.\n", "depends_on": [ 1, 2 ], "parent_issue": 1, "schema": "agent.developer_task.v1", "source_issue": 2, "title": "Implement 3: Complete the native-process CLI, JSON request handling, status vocabulary and exit codes", "workflow": { "base_branch": "master", "ci_status": "created", "created_branch": true, "created_repository": false, "facade_action": "initialize", "facade_path": ".agent/project.yaml", "facade_placement": { "kind": "repository_root" }, "facade_status": "initialized", "facade_template": "script_toolkit_python", "generated_by": "teamlead-agent", "project_shape": { "delivery_kind": "native_process", "interfaces": [ "cli" ], "languages": [ "python" ], "parameters": { "cli_entrypoint": { "default": "tools/example.py", "description": "Exact implementation path required before CLI checks may run.", "type": "relative_path" }, "cli_module": { "default": "tools.example", "description": "Importable CLI module selected by the architecture contract.", "type": "python_module" }, "package_module": { "default": "tools", "description": "Importable package name used by package acceptance checks.", "type": "python_module" }, "package_path": { "default": "tools", "description": "Python package directory implemented by the project.", "type": "relative_path" }, "sample_input_path": { "default": "examples/input.json", "description": "Project-owned fixture supplied to the smoke command.", "type": "relative_path" }, "test_entrypoint": { "default": "tests/test_example.py", "description": "Exact test artifact required before the test command may run.", "type": "relative_path" }, "tests_path": { "default": "tests", "description": "Test suite directory used by the standard test command.", "type": "relative_path" } }, "placement_kinds": [ "repository_root" ], "project_kind": "script_toolkit", "runtimes": [ "command_line" ], "template": "script_toolkit_python" }, "project_shape_requirement_refs": { "delivery_kind": [ "REQ-011" ], "interfaces": [ "REQ-001", "REQ-002", "REQ-009" ], "languages": [ "REQ-001", "REQ-011" ], "project_kind": [ "REQ-001", "REQ-011" ], "runtimes": [ "REQ-001", "REQ-011" ] }, "repository": "projects/product-54354138-1", "repository_intent": "existing_repository", "target_branch": "task/1-task", "task_branch": "task/1-task" } }