# Factory CWD Coupling Report

Audience: AI coding agents first.

Scope: reference SSSF only. Citations use paths rooted at `modules/harness/reference/sssf/`.

## Findings

1. **Installer target root. Needs a change.** `install.py` assigns `root = Path.cwd()`; every stamped destination is therefore under launch CWD: `adws/`, `adws/adw_data/prompt_engineering/`, `adws/adw_data/harness_engineering/`, `adws/adw_sssf_config/sssf.config.yaml`, `.env.sample`, `justfile`, and `.gitignore`. The `.gitignore` merge also uses that same root. This is correct for a per-target installer, but a shared factory needs an explicit `--target-root` (defaulting only deliberately, if retained). [scripts/install.py:51-58](modules/harness/reference/sssf/scripts/install.py#L51-L58) [scripts/install.py:66-82](modules/harness/reference/sssf/scripts/install.py#L66-L82)

2. **Runtime data directory. Needs a change.** `defaults.data_dir` is a config path whose documented default is `adws/adw_data`; `Run` appends `sessions/<adw_id>` without anchoring it to config location or a target-root parameter. With the documented relative default, session state resolves below launch CWD. [references/config.md:16-20](modules/harness/reference/sssf/references/config.md#L16-L20) [templates/adws/adw_modules/runner.py:53-56](modules/harness/reference/sssf/templates/adws/adw_modules/runner.py#L53-L56)

3. **Session event JSONL. Needs a change.** `session.ensure()` builds `"{cfg.defaults.data_dir}/sessions/{adw_id}/events.jsonl"` and passes it to `Tracer`. A relative `data_dir` therefore makes event JSONL CWD-relative. [templates/adws/adw_modules/session.py:38-42](modules/harness/reference/sssf/templates/adws/adw_modules/session.py#L38-L42)

4. **Observability database. Already configurable.** `observability.db` comes unchanged from configuration into `Tracer`; `Tracer` creates `Path(db_path).parent` and gives the original path to SQLite. The documented default `adws/adw_data/sssf.db` is CWD-relative, but no code rejects, rewrites, or joins an absolute path. An absolute `observability.db` can therefore be supplied. [references/config.md:54-59](modules/harness/reference/sssf/references/config.md#L54-L59) [templates/adws/adw_modules/session.py:38-42](modules/harness/reference/sssf/templates/adws/adw_modules/session.py#L38-L42) [templates/adws/adw_modules/tracer.py:102-109](modules/harness/reference/sssf/templates/adws/adw_modules/tracer.py#L102-L109)

5. **Config default and loader. Already configurable.** `agents.load_config()` reads the supplied path directly via `Path(path).read_text()`. Its default is the CWD-relative `adws/adw_sssf_config/sssf.config.yaml`, but `adw_prompt.py` exposes `--config` and forwards it to the loader. The reference documents this switch for any ADW and `SSSF_CONFIG` for justfile recipes. An absolute injected config path is accepted by this direct `Path(path)` use. [templates/adws/adw_modules/agents.py:33-41](modules/harness/reference/sssf/templates/adws/adw_modules/agents.py#L33-L41) [templates/adws/adw_prompt.py:20-24](modules/harness/reference/sssf/templates/adws/adw_prompt.py#L20-L24) [templates/adws/adw_prompt.py:37-44](modules/harness/reference/sssf/templates/adws/adw_prompt.py#L37-L44) [references/config.md:3-6](modules/harness/reference/sssf/references/config.md#L3-L6)

6. **CLI prompt-file argument. Needs a change.** `resolve_prompt()` treats its positional argument as a path and calls `Path(arg).is_file()` / `read_text()` directly. Thus a relative prompt-file argument resolves from launch CWD. A shared core should resolve such user-facing file arguments relative to an explicit target root or require an explicit path policy. [templates/adws/adw_modules/utils.py:55-63](modules/harness/reference/sssf/templates/adws/adw_modules/utils.py#L55-L63) [templates/adws/adw_prompt.py:37-44](modules/harness/reference/sssf/templates/adws/adw_prompt.py#L37-L44)

7. **Configured agent prompt files. Already configurable.** Each agent config contains independent `prompt_engineering.system` and `.user` paths. Validation checks each exact path, and rendering reads each exact configured path; neither operation copies or derives a prompt-tree location. A project can override one system or user prompt by supplying a config whose one field names a replacement file, including an absolute path, without copying the whole `prompt_engineering` tree. [references/config.md:29-36](modules/harness/reference/sssf/references/config.md#L29-L36) [references/config.md:65-74](modules/harness/reference/sssf/references/config.md#L65-L74) [templates/adws/adw_modules/agents.py:64-67](modules/harness/reference/sssf/templates/adws/adw_modules/agents.py#L64-L67) [templates/adws/adw_modules/agents.py:84-92](modules/harness/reference/sssf/templates/adws/adw_modules/agents.py#L84-L92) [templates/adws/adw_modules/prompts.py:8-12](modules/harness/reference/sssf/templates/adws/adw_modules/prompts.py#L8-L12)

8. **Prompt audit copies. Needs a change.** Rendered prompt copies are written under `run.session_dir/<agent>/prompts/`; because `session_dir` derives from potentially relative `data_dir`, these copies are CWD-relative under the default configuration. [templates/adws/adw_modules/agents.py:80-92](modules/harness/reference/sssf/templates/adws/adw_modules/agents.py#L80-L92) [templates/adws/adw_modules/prompts.py:15-21](modules/harness/reference/sssf/templates/adws/adw_modules/prompts.py#L15-L21)

9. **Git repository discovery. Needs a change.** `git_helper.is_repo()` and `repo_root()` run Git without a `cwd` argument. They consequently inspect the process CWD; `repo_root()` returns Git's toplevel found from there, or returns `Path.cwd()` for a non-Git directory. `Run` calls this no-argument function during construction, binding all later agent work to launch CWD's repository. Shared core needs an explicit target-root/repository argument propagated into this boundary. [templates/adws/adw_modules/git_helper.py:25-40](modules/harness/reference/sssf/templates/adws/adw_modules/git_helper.py#L25-L40) [templates/adws/adw_modules/runner.py:51-55](modules/harness/reference/sssf/templates/adws/adw_modules/runner.py#L51-L55)

10. **Git mutations and queries. Needs a change.** `_git()` runs every Git subprocess without an explicit working directory. Therefore all branch, commit, status, diff, ref, and merge-base operations inherit launch CWD: `current_branch`, `create_branch`, `commit_all`, `changed_files`, `ref_exists`, `rev`, `short_sha`, `merge_base`, `is_dirty`, `untracked_files`, `diff_files`, `diff_stat`, `diff_counts`, and `diff_text`. This requires a Git CWD parameter or a repository-bound helper instance. [templates/adws/adw_modules/git_helper.py:9-13](modules/harness/reference/sssf/templates/adws/adw_modules/git_helper.py#L9-L13) [templates/adws/adw_modules/git_helper.py:16-22](modules/harness/reference/sssf/templates/adws/adw_modules/git_helper.py#L16-L22) [templates/adws/adw_modules/git_helper.py:43-53](modules/harness/reference/sssf/templates/adws/adw_modules/git_helper.py#L43-L53) [templates/adws/adw_modules/git_helper.py:56-120](modules/harness/reference/sssf/templates/adws/adw_modules/git_helper.py#L56-L120)

11. **Agent subprocess working directory. Needs a change.** Agent execution deliberately passes `cwd=str(run.repo_root)` to the coding-agent request. This centralizes one process-wide CWD-derived choice, but does not permit the factory caller to select a target independently of launch CWD because `run.repo_root` comes from Finding 9. [templates/adws/adw_modules/agents.py:112-126](modules/harness/reference/sssf/templates/adws/adw_modules/agents.py#L112-L126) [templates/adws/adw_modules/runner.py:51-55](modules/harness/reference/sssf/templates/adws/adw_modules/runner.py#L51-L55)

12. **Engineer-name Git lookup. Needs a change.** `engineer_name()` invokes `git config user.name` without an explicit working directory. This is CWD-sensitive for repository-local Git configuration, although it has environment fallbacks. The factory should either treat engineer identity as an injected value or bind this lookup to the explicit target repository. [templates/adws/adw_modules/utils.py:66-77](modules/harness/reference/sssf/templates/adws/adw_modules/utils.py#L66-L77)

## Direct answers

- `observability.db` is the raw `observability.db` configuration value passed through `session.ensure()` to `Tracer`; its documented default is relative, but absolute paths work. Finding 4.
- Config defaults to `adws/adw_sssf_config/sssf.config.yaml`, loads through `Path(path).read_text()`, and supports path injection through `--config`; justfile also supports `SSSF_CONFIG`. Finding 5.
- Prompts are read from each agent's two configured paths. One prompt can be overridden by changing only its corresponding config field; no whole-tree copy is required. Finding 7.
- `git_helper` assumes CWD is the repository by running every Git subprocess without `cwd`; `repo_root()` discovers from that same CWD and falls back to it outside Git. Findings 9-10.
