{ "body": "\n\nTeam-lead source issue: #2\nParent architecture issue: #1\n\n## Developer Task\n\nBootstrap the toolkit tree, project config and initial dependency lock\n\n## Scope\n\nCreate the stable repository-root toolkit tree that every facade path depends on: the importable tools package (tools/__init__.py plus a minimal placeholder CLI module tools/example.py), tests/test_example.py, and examples/input.json as the canonical JSON request document (a validate-only dry_run request so `python -m tools.example examples/input.json` stays deterministic and offline). Adjust pyproject.toml (project metadata, pytest dev extra, pytest options so the repository root is importable from tests) and create the committed uv.lock through the supported dependency update operation, so no later task has to touch the manifest or the lock. No product behavior beyond loading and validating the request document and printing a single structured JSON envelope with exit code 0. This task establishes the tree that later tasks extend with additional modules and test files.\n\n## Acceptance Criteria\n\n- Affected file `tools/__init__.py` is `valid`.\n- Affected file `tools/example.py` is `valid`.\n- Affected file `tests/test_example.py` is `valid`.\n- Affected file `examples/input.json` is `valid`.\n- Affected file `pyproject.toml` is `valid`.\n- Affected file `uv.lock` is `exists`.\n- Capability `toolkit_layout` is `provided` by evidence `skeleton-init-module-valid`, `skeleton-cli-module-valid`, `skeleton-test-module-valid`, `example-request-document-valid`, `project-config-valid`.\n- Capability `locked_environment` is `provided` by evidence `project-config-valid`, `lockfile-present`.\n\n## Test Hints\n\n- Run Tool Backend prepare_environment(component='tools', update='tools', reason='create the initial uv.lock for the pytest dev extra') and commit the resulting uv.lock; do not add package sources, credentials or public-index fallbacks.\n- python -m compileall tools tests\n- python -m tools.example examples/input.json (must print one JSON document and exit 0)\n- pytest\n- tools/example.py\n- tests/test_example.py\n- examples/input.json\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- R11: `REQ-011` REQ-011 Утилита поставляется и запускается как обычный исполняемый процесс, без Docker и контейнеров.\n\n## Affected Repos / Files\n\n- pyproject.toml\n- uv.lock\n- tools\n- tests\n- tools/__init__.py\n- tools/example.py\n- tests/test_example.py\n- examples/input.json\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- `uv.lock`: state=`absent_at_planning`, intent=`create_final`, satisfies=`uv.lock`, required_by=`tools.dependencies.update`\n- `tools`: state=`absent_at_planning`, intent=`stable_skeleton`, satisfies=`tools`, `tools/example.py`, required_by=`tools.smoke`, `tools.validate`\n- `tests`: state=`absent_at_planning`, intent=`stable_skeleton`, satisfies=`tests`, `tests/test_example.py`, required_by=`tools.test`, `tools.validate`\n- `tools/__init__.py`: state=`absent_at_planning`, intent=`create_final`, satisfies=`tools`, required_by=`tools.validate`\n- `tools/example.py`: state=`absent_at_planning`, intent=`create_final`, satisfies=`tools`, `tools/example.py`, required_by=`tools.smoke`, `tools.validate`\n- `tests/test_example.py`: state=`absent_at_planning`, intent=`create_final`, satisfies=`tests`, `tests/test_example.py`, required_by=`tools.test`, `tools.validate`\n- `examples/input.json`: state=`absent_at_planning`, intent=`create_final`, satisfies=`examples/input.json`, required_by=`tools.smoke`\n\n## Required Dependency Updates\n\nThese structured operations must complete through Tool Backend `prepare_environment` before the task may finish.\n\n- component=`tools`, operation=`update`, required_outputs=`uv.lock`, required_declarations=[{\"dependency_role\": \"test\", \"id\": \"python_pytest\", \"kind\": \"project_dependency_requirement\", \"manifest_path\": \"pyproject.toml\", \"package\": {\"ecosystem\": \"python\", \"name\": \"pytest\"}, \"profile\": \"tool/python_pytest@1\", \"provision_source\": \"project_dependency\", \"state\": \"satisfied\"}]\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: `scaffold`\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- `pyproject.toml`: `modify_final`, ownership_scope=`exact_path`\n- `uv.lock`: `create_final`, ownership_scope=`exact_path`\n- `tools`: `stable_skeleton`, ownership_scope=`subtree`\n- `tests`: `stable_skeleton`, ownership_scope=`subtree`\n- `tools/__init__.py`: `create_final`, ownership_scope=`exact_path`\n- `tools/example.py`: `create_final`, ownership_scope=`exact_path` (allows internal placeholder)\n- `tests/test_example.py`: `create_final`, ownership_scope=`exact_path` (allows internal placeholder)\n- `examples/input.json`: `create_final`, ownership_scope=`exact_path`\n\n## Acceptance Checks\n\n- `skeleton-init-module-valid` `artifact_state` `affected_file:tools/__init__.py` expected=`valid`\n- `skeleton-cli-module-valid` `artifact_state` `affected_file:tools/example.py` expected=`valid`\n- `skeleton-test-module-valid` `artifact_state` `affected_file:tests/test_example.py` expected=`valid`\n- `example-request-document-valid` `artifact_state` `affected_file:examples/input.json` expected=`valid`\n- `project-config-valid` `artifact_state` `affected_file:pyproject.toml` expected=`valid`\n- `lockfile-present` `artifact_state` `affected_file:uv.lock` expected=`exists`\n- `toolkit-layout-provided` `capability_result` `capability:toolkit_layout` expected=`provided` evidence=skeleton-init-module-valid,skeleton-cli-module-valid,skeleton-test-module-valid,example-request-document-valid,project-config-valid\n- `locked-environment-provided` `capability_result` `capability:locked_environment` expected=`provided` evidence=project-config-valid,lockfile-present\n\n## Capability Contract\n\n- Provides: `toolkit_layout` (`structure`), `locked_environment` (`structure`)\n- Requires: _none_\n\n## Integration Contract\n\n- Functional dependencies: []\n- Execution predecessors: []\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- 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": [], "parent_issue": 1, "schema": "agent.developer_task.v1", "source_issue": 2, "title": "Implement 1: Bootstrap the toolkit tree, project config and initial dependency lock", "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" } }