Skip to content

feat: link once — ancestor walk-up for project links (git-style)#23

Merged
tonychang04 merged 1 commit into
mainfrom
fix/link-walk-up
Jul 12, 2026
Merged

feat: link once — ancestor walk-up for project links (git-style)#23
tonychang04 merged 1 commit into
mainfrom
fix/link-walk-up

Conversation

@tonychang04

@tonychang04 tonychang04 commented Jul 12, 2026

Copy link
Copy Markdown
Member

"Link once and let it work": previously the CLI only checked the exact cwd for .insta/project.json, so commands failed from subdirectories and a branch switch in src/ minted a nested second link. Now git-style: readProject walks up to the nearest ancestor link; writeProject updates the found root. Committing .insta/project.json already gives the team/CI the binding on clone — with walk-up, insta's link UX now beats Railway's per-machine registry (their teammates must link by hand). TDD: 3 red→green tests; 47/47.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GMbAe5K1RfwaAcge5inX7P


Summary by cubic

Add git-style ancestor walk-up for .insta/project.json so you can link once and run commands from any subdirectory. Prevents nested links; branch switches now update the root link.

  • New Features
    • readProject walks up to find the nearest .insta/project.json.
    • writeProject writes to the found root; falls back to cwd only when unlinked.

Written for commit eca2b67. Summary will update on new commits.

Review in cubic

readProject resolves the nearest ancestor link, so every command works
from any subdirectory of a linked project; writeProject targets the found
root (branch switch in src/ no longer mints a nested link). Fresh links
in unlinked trees still bind cwd.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GMbAe5K1RfwaAcge5inX7P

@jwfing jwfing left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - approved.

@tonychang04
tonychang04 merged commit 0cd1e52 into main Jul 12, 2026
2 checks passed
@tonychang04 tonychang04 mentioned this pull request Jul 12, 2026

@jwfing jwfing left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: feat: link once — ancestor walk-up for project links

Summary: Clean, well-tested implementation of git-style ancestor walk-up for .insta/project.json; no blocking issues, but the walk-up-on-write also changes the semantics of the link-establishing commands, which is worth a look.

Requirements context

No matching spec/plan found — this repo has no docs/superpowers/, docs/specs/, or docs/ directory at all. Assessed against the PR description/title and the intent stated in the code comments alone.

Findings

Critical

(none)

Suggestion

  • Functionality — walk-up on write silently repoints an ancestor link for link-establishing commands (src/config.ts:67-71). writeProject now walks up unconditionally, but it's shared by three call sites with different intents:

    • branchSwitch (src/commands/branch.ts:25) — mutates an existing link. Walk-up is exactly the fix you want here. ✅
    • projectCreate (src/commands/project.ts:26) and projectLink (src/commands/project.ts:46) — these establish a binding. With walk-up, running insta project link <id> or insta project create from a subdirectory of an already-linked tree no longer creates a link at cwd — it overwrites the nearest ancestor .insta/project.json. Since the walk climbs to the filesystem root, a single stray link high in the tree (e.g. an accidental ~/.insta/project.json) makes every project link/create under $HOME silently repoint that one link instead of linking the current directory — effectively making it impossible to link a second project in the subtree. The overwrite is usually recoverable via git, but it's surprising. Consider having link-establishing commands (project link/project create) target cwd and reserving walk-up for the mutating path (branch switch), e.g. a writeProject(c, cwd, { walkUp }) flag. This is a judgment call and consistent with the "link once" philosophy, so non-blocking — but worth a deliberate decision.
  • Software engineering — missing test for the case above (test/project-link.test.ts). The two claimed behaviors and the null case are well covered. Not covered: project link/create invoked from a subdirectory of an existing link. Given the semantic change above, a test pinning the intended behavior (whether it overwrites the root or links at cwd) would prevent a future regression either way.

Information

  • Performance — double read of project.json (src/config.ts:42-63). findProjectRoot reads the file to locate the root, then readProject reads and parses it again. Having findProjectRoot return the file contents (or readProject parse what it already read) would halve the I/O. Negligible in practice for a CLI; noting only.
  • Correctness (edge) — findProjectRoot's catch swallows all errors (src/config.ts:45-48). A permission error (EACCES) on a real link, or a malformed-JSON nearest link, is treated the same as "not here": the malformed case makes readProject return null without continuing to a valid ancestor. This matches the prior single-directory behavior (which also returned null on bad JSON), so no regression — just be aware a broken nearest link masks a good ancestor.
  • Design note — walk-up to filesystem root is intended git-style behavior. The loop correctly terminates at the fs root (parent === dir), and this mirrors how git resolves .git. Flagged only to make the "ancestor anywhere up to /" reach explicit, since it underpins the Suggestion above.

Security: No security-relevant changes. No new user input reaches SQL/shell/HTTP; project.json holds projectId/orgId/branch (not secrets); nothing new is logged or returned. Filesystem reads are read-only ancestor walks.

Coding standards: Matches repo conventions — node: import prefixes, .js extension on relative imports, clear intent-comments, resolve() for normalization. Import additions (dirname, resolve) are all used.

Verdict

approved — zero Critical findings. The Suggestion items are worth a look (especially the link-establishing-command semantics) but none block merge. (This is an informational review; explicit GitHub approval remains a separate human action.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants