Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion .agent/skills/bootstrap-clever-work/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@ The canonical identifier is the created `project-start` issue number in `clever-

When a new target repo is created or bootstrapped, keep execution rules and planning content separate:

Use this local folder layout unless the user has explicitly provided another path:

```text
<CLEVER_ROOT>/
clever-agent-workspace/
clever-agent-project/
clever-context-monorepo/
clever-change-control/
projects/
<project-slug>/
<target-repo>/
```

The three agent/control-plane repositories stay under `<CLEVER_ROOT>/clever-agent-workspace/`.
Remote product/service repositories are cloned or pulled under
`<CLEVER_ROOT>/projects/<project-slug>/<target-repo>/`. Seed files are copied
into that target repo root.

- `AGENTS.md`: agent execution procedure, working order, issue/branch rules, verification, context update checks, and completion conditions
- `docs/project-brief.md`: project planning draft, purpose, constraints, scope, open questions, and next work list

Expand All @@ -51,6 +69,13 @@ python3 scripts/bootstrap_clever_work.py --cwd "$PWD" --preflight --current-repo
Interpret the result like this:

- `preflight_check.ready=false`: stop and show the failed checks before asking startup questions.
- Always read `workspace_check.session_open_check` before startup questions. The
Python preflight must confirm the CLEVER_ROOT-based session layout first:
three control-plane repos under `<CLEVER_ROOT>/clever-agent-workspace/`, target
repos under `<CLEVER_ROOT>/projects/<project-slug>/<target-repo>/`.
- Always read `preflight_check.agent_response_contract` before replying to a
CLEVER_ROOT-level prompt. It defines the response style: inherit the CLEVER
agent workflow, complete initial setup, then continue with the provided prompt.
- `preflight_check.ready=true`: continue by reading `workspace_check.agent_action`.
- `auto_skipped_questions`: do not ask these questions again; tool evidence already answered them.
- `recovery_actions`: use these concrete commands/actions to fix failed checks before continuing.
Expand Down Expand Up @@ -365,7 +390,7 @@ Once the user approves:
- 새 target repo는 public으로 생성한다.
- Use `gh repo create <owner>/<repo> --public` for a newly created target repo.
- GitHub Free organization rulesets are enforced on public repositories; private repository enforcement requires GitHub Team, GitHub Pro, or GitHub Enterprise Cloud.
5. Clone or pull the target repo locally.
5. Clone or pull the target repo under `<CLEVER_ROOT>/projects/<project-slug>/<target-repo>/`.
6. Copy the target repo seed files before handoff:
- `docs/templates/target-repo-AGENTS.md` -> target repo `AGENTS.md`
- `docs/templates/target-repo-project-brief.md` -> target repo `docs/project-brief.md`
Expand All @@ -383,6 +408,37 @@ Once the user approves:
- default new work to task branches from `dev` unless the work is intentionally direct-on-`dev`
9. Recommend a new session in the cloned target repo for planning or implementation.

### Scoped Target Work After Bootstrap

For every non-trivial development task after the target repo exists, the agent
must treat the request as a GitHub issue-linked workflow before editing files:

1. Create or identify the target repository issue.
2. Create or identify the matching `clever-change-control` issue when scoped
change tracking is needed.
3. Link both issues with explicit mentions.
4. Create the branch only through GitHub Development:

```bash
gh issue develop <target-issue-number> \
--repo <target-repo-full-name> \
--base dev \
--name cc-<change-control-issue-number>-<short-scope> \
--checkout
```

5. Verify the linked branch:

```bash
gh issue develop --list <target-issue-number> \
--repo <target-repo-full-name>
```

Do not use `git checkout -b` first. Do not implement, commit, or open a PR until
the issue link and GitHub Development linked branch are ready. PRs for normal
work branch into `dev`, and PR bodies list the target issue plus the
`clever-change-control` issue.

Only after the root issue is approved and the execution scope is fixed should a scoped change request introduce a `change-id`.

Do not create service-doc drafts in the normal start path.
Expand Down
153 changes: 150 additions & 3 deletions .agent/skills/bootstrap-clever-work/scripts/bootstrap_clever_work.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

CONTEXT_REPO_NAME = "clever-context-monorepo"
CHANGE_REPO_NAME = "clever-change-control"
AGENT_WORKSPACE_DIR_NAME = "clever-agent-workspace"
PROJECTS_DIR_NAME = "projects"
START_REPO_NAME = "clever-agent-project"
CONTROL_PLANE_REPOS = (
START_REPO_NAME,
Expand Down Expand Up @@ -245,6 +247,16 @@ def is_checkout_root(path: Path) -> bool:


def infer_workspace_root(start: Path, git_root: Path | None = None) -> Path:
"""Return the control-plane root that contains the three agent repos.

Preferred layout:

<CLEVER_ROOT>/clever-agent-workspace/{three control-plane repos}
<CLEVER_ROOT>/projects/<project-slug>/<target-repo>

Legacy direct layout is still recognized so existing local checkouts can report
a useful migration-oriented preflight instead of failing path discovery.
"""
seen: set[Path] = set()
candidates: list[Path] = list(iter_ancestors(start))
if git_root is not None:
Expand All @@ -255,6 +267,11 @@ def infer_workspace_root(start: Path, git_root: Path | None = None) -> Path:
if resolved in seen:
continue
seen.add(resolved)

nested_control_root = resolved / AGENT_WORKSPACE_DIR_NAME
if any((nested_control_root / repo_name_value).exists() for repo_name_value in CONTROL_PLANE_REPOS):
return nested_control_root.resolve()

if any((resolved / repo_name_value).exists() for repo_name_value in CONTROL_PLANE_REPOS):
return resolved

Expand All @@ -263,6 +280,58 @@ def infer_workspace_root(start: Path, git_root: Path | None = None) -> Path:
return start.resolve()


def derive_clever_work_root(control_plane_root: Path) -> Path:
if control_plane_root.name == AGENT_WORKSPACE_DIR_NAME:
return control_plane_root.parent.resolve()
return control_plane_root.resolve()


def is_relative_to_path(path: Path, parent: Path) -> bool:
try:
path.resolve().relative_to(parent.resolve())
except ValueError:
return False
return True


def build_session_open_check(*, cwd: Path, control_plane_root: Path, current_repo: str | None) -> dict[str, Any]:
clever_work_root = derive_clever_work_root(control_plane_root)
expected_control_plane_root = clever_work_root / AGENT_WORKSPACE_DIR_NAME
projects_root = clever_work_root / PROJECTS_DIR_NAME
uses_expected_nested_layout = control_plane_root.resolve() == expected_control_plane_root.resolve()
cwd_under_control_plane = is_relative_to_path(cwd, control_plane_root)
cwd_under_projects = is_relative_to_path(cwd, projects_root)
opened_from_start_repo = current_repo == START_REPO_NAME and cwd_under_control_plane
opened_from_control_plane_repo = current_repo in CONTROL_PLANE_REPOS and cwd_under_control_plane

if uses_expected_nested_layout:
status = "pass" if (opened_from_control_plane_repo or cwd_under_projects) else "fail"
layout_mode = "clever-root-with-agent-workspace"
else:
status = "legacy-layout" if opened_from_control_plane_repo else "fail"
layout_mode = "legacy-direct-control-plane-root"

return {
"status": status,
"layout_mode": layout_mode,
"clever_root": str(clever_work_root),
"control_plane_root": str(control_plane_root),
"expected_control_plane_root": str(expected_control_plane_root),
"projects_root": str(projects_root),
"cwd_under_control_plane_root": cwd_under_control_plane,
"cwd_under_projects_root": cwd_under_projects,
"opened_from_start_repo": opened_from_start_repo,
"opened_from_control_plane_repo": opened_from_control_plane_repo,
"message": (
"Session path matches the CLEVER_ROOT layout."
if status == "pass"
else "Session uses the legacy direct control-plane layout; prefer <CLEVER_ROOT>/clever-agent-workspace for the three agent repos."
if status == "legacy-layout"
else "Session is not opened from the expected CLEVER_ROOT control-plane or projects layout."
),
}


def probe_repo_checkout(
*,
clever_root: Path,
Expand Down Expand Up @@ -291,6 +360,11 @@ def build_workspace_check(start: Path, *, current_repo_maintenance: bool = False
branch_name = current_branch(git_root) if git_root else None
preferred_checkout_name = git_root.name if git_root else None
clever_root = infer_workspace_root(cwd, git_root)
session_open_check = build_session_open_check(
cwd=cwd,
control_plane_root=clever_root,
current_repo=current_repo,
)

repos: dict[str, dict[str, Any]] = {}
missing_repositories: list[str] = []
Expand Down Expand Up @@ -351,6 +425,10 @@ def build_workspace_check(start: Path, *, current_repo_maintenance: bool = False
"current_repo": current_repo,
"current_branch": branch_name,
"clever_root": str(clever_root),
"clever_work_root": session_open_check["clever_root"],
"control_plane_root": session_open_check["control_plane_root"],
"projects_root": session_open_check["projects_root"],
"session_open_check": session_open_check,
"control_plane_complete": control_plane_complete,
"current_repo_is_start": current_repo_is_start,
"current_repo_maintenance_requested": current_repo_maintenance,
Expand Down Expand Up @@ -660,6 +738,56 @@ def build_preflight_next_questions(
return questions


def build_agent_response_contract(workspace_check: dict[str, Any]) -> dict[str, Any]:
agent_action = workspace_check.get("agent_action")
session_open_check = workspace_check.get("session_open_check") or {}
initial_steps = [
"do not start implementation directly from a free-form prompt",
"inherit the CLEVER agent-based workflow from clever-agent-project",
"confirm the CLEVER_ROOT session layout with workspace_check.session_open_check",
"create or confirm the target repository only after the project-start gate",
"apply or confirm repository rules before normal development",
"clone or pull the target repo under <CLEVER_ROOT>/projects/<project-slug>/<target-repo>",
"inject AGENTS.md, docs/project-brief.md, PR template, and ruleset script into the target repo root",
"after initial setup succeeds, continue according to the user's provided prompt",
]
if agent_action == "switch-to-clever-agent-project":
immediate_reply = (
"현재 세션은 CLEVER_ROOT 또는 control-plane 시작 위치로 감지했습니다. "
"바로 작업을 시작하지 않고 `clever-agent-workspace/clever-agent-project`의 "
"에이전트 기반 절차를 먼저 전수받아 preflight와 초기 세팅을 진행하겠습니다."
)
elif agent_action == "proceed-with-hard-gate":
immediate_reply = (
"에이전트 기반 preflight가 통과했습니다. 바로 구현하지 않고 작업 시작 정보를 "
"정규화한 뒤 project-start, repo bootstrap, 규칙 적용, pull/clone, 에이전트 문서 "
"주입 순서로 진행하겠습니다."
)
elif agent_action == "current-repo-maintenance":
immediate_reply = (
"현재 작업은 control-plane repo maintenance로 감지했습니다. 해당 repo 범위에서만 "
"에이전트 절차를 적용하고 일반 target repo bootstrap으로 내려가지 않겠습니다."
)
else:
immediate_reply = (
"CLEVER_ROOT 기반 세션 검증이 아직 완료되지 않았습니다. 작업을 시작하지 않고 "
"누락된 agent workspace와 3대 레포 구성을 먼저 복구하겠습니다."
)

return {
"do_not_start_freeform_work": True,
"session_open_status": session_open_check.get("status"),
"agent_action": agent_action,
"initial_steps": initial_steps,
"immediate_reply_style": immediate_reply,
"after_initial_setup_success_reply_style": (
"초기 작업(레포 확인/생성, repo 규칙 생성 또는 확인, pull/clone, "
"에이전트 문서 주입)이 완료됐습니다. 다음 작업은 주신 프롬프트대로 "
"<normalized-next-work>를 진행하겠습니다."
),
}


def build_preflight_check(
*,
cwd: Path,
Expand Down Expand Up @@ -1012,6 +1140,7 @@ def build_preflight_check(
workspace_check=workspace_check,
github_login=github_login,
)
agent_response_contract = build_agent_response_contract(workspace_check)
return {
"mode": mode,
"ready": ready,
Expand All @@ -1024,6 +1153,7 @@ def build_preflight_check(
"auto_skipped_questions": auto_skipped_questions,
"recovery_actions": recovery_actions,
"next_questions": next_questions,
"agent_response_contract": agent_response_contract,
}


Expand Down Expand Up @@ -1346,10 +1476,21 @@ def build_packet(
"visibility_reason": visibility_reason,
"status": "proposed-after-approval",
"proposal": repo_bootstrap_proposal,
"local_folder_layout": {
"control_plane_root": "<CLEVER_ROOT>/clever-agent-workspace",
"control_plane_repositories": [
"clever-agent-project",
"clever-context-monorepo",
"clever-change-control",
],
"project_repositories_root": "<CLEVER_ROOT>/projects/<project-slug>",
"target_repo_checkout": "<CLEVER_ROOT>/projects/<project-slug>/<target-repo>",
"seed_injection_root": "target repo root",
},
"post_create_clone": [
"create-or-confirm public target repo after project-start approval",
"clone-or-pull the target repo locally",
"copy target repo seed files before handoff",
"clone-or-pull the target repo under <CLEVER_ROOT>/projects/<project-slug>/<target-repo>",
"copy target repo seed files into the target repo root before handoff",
"apply GitHub rulesets after dev exists",
"verify local checkout is ready for follow-on work",
],
Expand All @@ -1362,7 +1503,7 @@ def build_packet(
},
"next_step": (
"Present the project-start draft for approval. After approval, create the issue, "
"propose repo bootstrap, clone or pull the target repo, seed the target repo, "
"propose repo bootstrap, clone or pull the target repo under the projects folder, seed the target repo, "
"and recommend a new target-repo session."
),
}
Expand Down Expand Up @@ -1463,6 +1604,12 @@ def print_workspace_check(workspace_check: dict[str, Any]) -> None:
print(f"git-root: {workspace_check['git_root']}")
print(f"current-repo: {workspace_check['current_repo']}")
print(f"clever-root: {workspace_check['clever_root']}")
print(f"clever-work-root: {workspace_check['clever_work_root']}")
print(f"control-plane-root: {workspace_check['control_plane_root']}")
print(f"projects-root: {workspace_check['projects_root']}")
session_open_check = workspace_check.get("session_open_check", {})
print(f"session-open-check: {session_open_check.get('status')}")
print(f"session-open-message: {session_open_check.get('message')}")
print(
"control-plane-complete: "
f"{'yes' if workspace_check['control_plane_complete'] else 'no'}"
Expand Down
Loading