Skip to content

Execution Log: the env file the CLI config names

Append-only log of progress for the user's visibility.

Phase transitions

PhaseEnteredReviewed/approved byNotes
phase-selection2026-09-03Tier 3 (human-approves-pr; below security.review.humanSignOffMinTier: 4): one new stdlib module, one resolver on cli_config, three entry-point calls, and one additive block in cli-config.schema.json (an autonomy.sensitivePaths entry — hence not tier 2); no authorization, routing or workflow path is touched. Brainstorming skipped — the ticket's two bullets are the requirements. No authorized the-loop execute reaches this cloud session, so the selection is recorded here and every phase is walked
requirements-definition2026-09-03requirements.md — three requirements, five abuse cases
design2026-09-03design.md — a stdlib loader, a resolver on the CLI config, three entry points; decision-108
test-planning2026-09-03testing-plan.md — thirteen rows, six applicable
tasks-breakdown2026-09-03tasks.md — six tasks
implementation2026-09-03On claude/github-issue-318-m5e70p
verification2026-09-03evidence/verification.md — rows T1, T2, T8, T10, T12; evidence/security-review.md — five abuse cases, five closed
needs-review2026-09-03PR raised; awaiting the owner (tier 3: human-approves-pr)
complete

Pull requests

PRScope / tasksStatus
#320tasks 1–6: the whole work itemopen

Progress entries

2026-09-03 — implemented, verified, ready for review

  • Phase: implementation → verification → needs-review
  • Did: tasks 1–6, red first each. the_loop.envfile (parse, load, the two result dataclasses); cli_config.resolve_env_file and load_env_file (config-relative, ~ expanded, a strict-and-silent config read, the version gate, never raises); the call first in cli.main, daemon_entry.main and api/serve.main; the env block in the authored schema and its packaged copy; the two scenarios; the docs, the template, this repo's config, the capability doc, decision-108.
  • Checkpoint/tests: make check — see evidence/verification.md. New tests: 20 unit (grammar, loader, resolver, entry points), 2 scenarios. No existing assertion changed.
  • Self-review: three passes over the diff. Fixed in place: the loader read the config leniently, which logged "could not parse" once here and once again from the command (now a strict read that returns quietly — the command reports once); a stale config loaded the env file before the command refused it (the test for R2.6 caught it; the loader now runs assert_current). Pass three found nothing new.
  • Next: the owner's review.
  • Blockers: none.

2026-09-03 — spec chain drafted

  • Phase: requirements-definition → tasks-breakdown
  • Did: read cli_config.py, cli.py, daemon_entry.py, api/serve.py, core/daemons.py and core/lifecycle.py at 31b1183; found that every the-loop process starts through one of three entry points and that the two spawners pass no env=, so children inherit; found every secret is already read by a config-declared name from os.environ; wrote the four artifacts and the decision.
  • Checkpoint/tests: baseline — test_cli_config.py green (24 passed).
  • Next: task 1 (the loader), red first.
  • Blockers: none.

Verification results

Only when this work item declared test-planning away. It did not: results live in testing-plan.md.

What was verifiedCommandOutcomeEvidence
see testing-plan.md

Design critic review

Not selected for this work item.

RoundCritic (<harness>/<model>)OutcomeFindings → dispositionLink

Review cycles

CycleType (self/critic/security)ReviewerOutcomeLink
1selfthe-loop (this session)new findings — the duplicated "could not parse" warning; the stale config loading the file: fixedthis log
2selfthe-loop (this session)zero (converged)this log
3selfthe-loop (this session)zero (converged)this log
criticunavailable — reviews.critics is empty in this repository's config; does not count toward criticReviewCount
4securitythe-loop checklistpass; no human sign-off at tier 3evidence/security-review.md

Security review (gate)

  • Mechanism: the-loop checklist (security.review.mechanism: auto; no security-review skill is invocable from this session's plugin set)
  • Outcome: pass — evidence/security-review.md, five abuse cases closed
  • Human sign-off: n/a (tier 3 is below humanSignOffMinTier: 4)

Final validation evidence

RequirementProof
R1.1 env.file accepted; unset → nothingtest_a_config_without_an_env_block_loads_nothing; make validate (schema); test_config_schema_parity.py
R1.2 loaded first by every entry pointtest_the_cli_loads_the_env_file_before_building_the_parser, test_the_daemon_entry_loads_the_env_file_before_running, test_the_service_loads_the_env_file_before_its_config; Scenario: The Slack token comes from the env file the config names
R1.3 config-relative, ~ expandedtest_a_relative_path_resolves_against_the_config_directory, test_tilde_is_expanded, test_an_absolute_or_parent_path_is_honoured_and_named; the scenario runs from an unrelated cwd
R1.4 the grammar; no interpolationtest_the_grammar_reads_plain_export_and_quoted_lines, test_the_grammar_does_not_interpolate, test_the_grammar_lets_a_later_duplicate_win, test_the_grammar_reports_invalid_lines_by_number
R1.5 the environment winstest_the_environment_wins_over_the_file; Scenario: A token exported in the shell wins over the file
R1.6 children inherit and re-loadthe two spawners pass no env= (unchanged, read at 31b1183); the daemon-entry and service tests above
R2.1 missing / not regular → warning, nothingtest_a_missing_file_warns_and_loads_nothing, test_a_directory_is_not_a_regular_file
R2.2 malformed line → skipped by numbertest_malformed_lines_are_skipped_by_number_and_the_rest_loaded
R2.3 unreadable → warning with the error classtest_an_unreadable_file_warns_with_the_error_class
R2.4 readable by others → warning, still loadedtest_a_file_readable_by_others_is_warned_about_and_still_loaded
R2.5 no value in any recordtest_a_warning_never_carries_a_value_or_a_line
R2.6 the lenient config readtest_a_stale_or_broken_config_loads_nothing_and_does_not_raise; the scenario runs --version
R3.1 documented, parity greentest_docs_parity.py (P3, P4, P5)
R3.2 template + this repo's configmake validate — both VALID with the block
R3.3 the guides point at itdocs/cli/getting-started.md, docs/cli/receiver.md, webhook-options.md, channels-options.md (markdownlint green)
A1–A5evidence/security-review.md

Capability docs

Capability docWhat changedHistory row
cli.mda new current-behaviour bullet: the CLI config MAY name an env file that every entry point loads first, at start — stdlib parser, config-relative, the environment never overwritten, the lenient config read, failures warned without a value, no re-read on reload, not loaded by the SDKissue-318 row

Documentation

DocumentWhat changed
docs/config/cli/index.md§ Environment file: the env.file option (type, default, resolution rule, the grammar, the failure modes, the config-names-a-path warning)
docs/cli/getting-started.mdthe webhook export line: the env file as the alternative
docs/cli/receiver.md§ Verification: the environment can come from the file the config names
docs/config/cli/webhook-options.md, docs/config/cli/channels-options.mdthe secretEnv / botTokenEnv paragraphs point at env.file
skills/the-loop/templates/cli-config.yaml, .the-loop/cli-config.yamlthe env block, commented, unset
.the-loop/cli-config.schema.json, cli/the_loop/schemas/cli-config.schema.jsonthe env block (byte-identical copies)
docs/decisions/decision-108.md, decisions.mdthe decision and its index row
README.md, skills/the-loop/SKILL.mdunchanged — neither describes how secrets reach the daemons

Released under the MIT License.