Skip to content

Commit adb7732

Browse files
committed
fix: separate config root from working directory
The CLI always did os.chdir(root), so running `scagent` from a directory without .pi/SYSTEM.md (e.g. a new project) would silently teleport you to the package's install directory. Now resolve_roots() returns (config_root, work_dir) separately: - Inside a scAgent project: both point to the project (as before) - From any other directory: config loads from the installed package, but the working directory stays as the user's cwd Same fix applied to scagent.sh.
1 parent 9f17f0a commit adb7732

File tree

2 files changed

+64
-33
lines changed

2 files changed

+64
-33
lines changed

scagent.sh

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212

1313
set -euo pipefail
1414

15-
# Where the shell script (and package) lives — fallback only
15+
# Where the script (and package) lives — used for config fallback
1616
SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")")" && pwd)"
1717

18-
# Resolve project root: prefer cwd (or ancestor), fall back to script dir
19-
find_root() {
20-
# Walk up from cwd
18+
# Resolve config root + working directory
19+
# Priority: cwd project > script location (config only)
20+
find_local_project() {
2121
local dir="$PWD"
2222
while true; do
2323
if [ -f "$dir/.pi/SYSTEM.md" ]; then
@@ -28,16 +28,22 @@ find_root() {
2828
[ "$parent" = "$dir" ] && break
2929
dir="$parent"
3030
done
31-
# Fallback: script's own directory
32-
if [ -f "$SCRIPT_DIR/.pi/SYSTEM.md" ]; then
33-
echo "$SCRIPT_DIR"
34-
return
35-
fi
36-
echo "Error: Could not find scAgent project root (.pi/SYSTEM.md)." >&2
37-
exit 1
31+
return 1
3832
}
3933

40-
SCAGENT_DIR="$(find_root)"
34+
WORK_DIR="$PWD"
35+
36+
if LOCAL="$(find_local_project)"; then
37+
# Running inside a scAgent project — use it for config + working dir
38+
CONFIG_ROOT="$LOCAL"
39+
WORK_DIR="$LOCAL"
40+
elif [ -f "$SCRIPT_DIR/.pi/SYSTEM.md" ]; then
41+
# No local project — use script's config, stay in user's directory
42+
CONFIG_ROOT="$SCRIPT_DIR"
43+
else
44+
echo "Error: Could not find scAgent project root (.pi/SYSTEM.md)." >&2
45+
exit 1
46+
fi
4147

4248
if ! command -v feynman >/dev/null 2>&1; then
4349
echo "Error: Feynman is not installed." >&2
@@ -46,6 +52,6 @@ if ! command -v feynman >/dev/null 2>&1; then
4652
exit 1
4753
fi
4854

49-
export FEYNMAN_CODING_AGENT_DIR="$SCAGENT_DIR/.pi"
50-
cd "$SCAGENT_DIR"
55+
export FEYNMAN_CODING_AGENT_DIR="$CONFIG_ROOT/.pi"
56+
cd "$WORK_DIR"
5157
exec feynman "$@"

scagent/cli.py

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,51 @@
1010
from pathlib import Path
1111

1212

13-
def find_scagent_root() -> Path:
14-
"""Find the scAgent project root by locating .pi/SYSTEM.md."""
15-
# 1. Explicit env var
16-
env_root = os.environ.get("SCAGENT_ROOT")
17-
if env_root:
18-
root = Path(env_root)
19-
if (root / ".pi" / "SYSTEM.md").exists():
20-
return root
13+
def _package_root() -> Path | None:
14+
"""Return the scAgent project root next to the installed package, if valid."""
15+
package_dir = Path(__file__).resolve().parent # scagent/
16+
project_dir = package_dir.parent # scAgent/
17+
if (project_dir / ".pi" / "SYSTEM.md").exists():
18+
return project_dir
19+
return None
20+
2121

22-
# 2. Walk up from cwd (preferred — lets you run from any scAgent project)
22+
def _find_local_project() -> Path | None:
23+
"""Walk up from cwd to find a directory with .pi/SYSTEM.md."""
2324
cwd = Path.cwd()
2425
for parent in [cwd, *cwd.parents]:
2526
if (parent / ".pi" / "SYSTEM.md").exists():
2627
return parent
28+
return None
2729

28-
# 3. Installed package location (fallback — editable installs point here)
29-
package_dir = Path(__file__).resolve().parent
30-
project_dir = package_dir.parent
31-
if (project_dir / ".pi" / "SYSTEM.md").exists():
32-
return project_dir
30+
31+
def resolve_roots() -> tuple[Path, Path]:
32+
"""Return (config_root, work_dir).
33+
34+
- config_root: where .pi/ lives (system prompt, skills, tool schemas)
35+
- work_dir: where feynman should run (where the user's data is)
36+
37+
Priority:
38+
1. SCAGENT_ROOT env var → config + work dir
39+
2. Local project (cwd ancestor) → config + work dir
40+
3. Package location → config only, work dir stays as cwd
41+
"""
42+
# 1. Explicit env var — full override
43+
env_root = os.environ.get("SCAGENT_ROOT")
44+
if env_root:
45+
root = Path(env_root)
46+
if (root / ".pi" / "SYSTEM.md").exists():
47+
return root, root
48+
49+
# 2. Local project in cwd tree — use it for both
50+
local = _find_local_project()
51+
if local:
52+
return local, local
53+
54+
# 3. No local project — use package config but stay in cwd
55+
pkg = _package_root()
56+
if pkg:
57+
return pkg, Path.cwd()
3358

3459
print("Error: Could not find scAgent project root (.pi/SYSTEM.md).", file=sys.stderr)
3560
print("Either:", file=sys.stderr)
@@ -40,7 +65,7 @@ def find_scagent_root() -> Path:
4065

4166
def main():
4267
"""Entry point for the scagent command."""
43-
root = find_scagent_root()
68+
config_root, work_dir = resolve_roots()
4469

4570
# Find feynman
4671
feynman = shutil.which("feynman")
@@ -53,12 +78,12 @@ def main():
5378
print("Then run: feynman setup", file=sys.stderr)
5479
sys.exit(1)
5580

56-
# Set the agent config to scAgent's .pi/ directory
57-
os.environ["FEYNMAN_CODING_AGENT_DIR"] = str(root / ".pi")
81+
# Point feynman at the scAgent config
82+
os.environ["FEYNMAN_CODING_AGENT_DIR"] = str(config_root / ".pi")
5883

59-
# Launch feynman from the project root
84+
# Launch feynman in the working directory
6085
args = [feynman] + sys.argv[1:]
61-
os.chdir(root)
86+
os.chdir(work_dir)
6287
os.execvp(args[0], args)
6388

6489

0 commit comments

Comments
 (0)