# Oh My Feed — 로컬 CLI MVP

프로젝트에 필요한 AI 도구 후보를 공식 출처와 함께 좁히고, 사용자가 승인한 계획으로 로컬 적용·검증을 이어갑니다. 공개 탐색에는 OMF 계정이나 별도 LLM API key가 필요하지 않습니다. 선택적으로 웹 계정을 연결하면 Saved와 관심 주제를 읽습니다. 이 문서의 계정 연결·적용 명령은 구현 계약이며 운영 배포 완료 안내가 아닙니다.

## 설치

Node.js 22 이상, macOS 또는 Linux가 필요합니다. Git 저장소를 클론하지 않고 운영 서비스에서 설치 파일을 직접 받습니다. 설치 이후 카탈로그도 `https://ohmyfeed.stream/data/catalog.json`에서 가져옵니다.

```sh
bash -o pipefail -c 'curl -fsS https://ohmyfeed.stream/install.sh | sh'
```

한 줄로 운영 설치 스크립트를 실행합니다. `pipefail`은 다운로드 실패를 실패 종료로 전달합니다. 스크립트를 검토하려면 [install.sh](https://ohmyfeed.stream/install.sh)를 먼저 읽을 수 있습니다. 내부에서는 비공개 임시 폴더를 사용하고 HTTPS로 받은 manifest와 각 파일의 SHA-256을 대조합니다. 이 검사는 전송/배포 파일 일관성 확인이며 별도 서명이나 제3자 보안 인증은 아닙니다.

기본 실행 파일은 `~/.omf/bin/omf`, 사용자 데이터는 `~/.omf/data`, 검증된 프로그램은 `~/.omf/releases`에 둡니다. shell 시작 파일이나 기존 Codex/Claude hook은 변경하지 않습니다. 기본으로 두 client 스킬을 설치합니다. `--client codex`, `--client claude`, `--client none` 옵션을 전달할 때는 마지막 부분을 `sh -s -- --client codex`처럼 바꿉니다. 기존 사용자 파일은 보존합니다.

특정 프로젝트에만 skill을 설치하려면 `--scope project --project /path/to/project`를 추가합니다. 기본 user scope는 `~/.agents/skills/`와 `~/.claude/skills/` 아래에 `oh-my-feed`(탐색·적용)와 `oh-my-feed-login`(계정 연결) 두 스킬을 둡니다. Codex/Claude Code를 새로 시작한 뒤 Codex에서는 `$oh-my-feed`, Claude Code에서는 `/oh-my-feed`를 호출합니다. 계정 연결은 `$oh-my-feed-login` 또는 `/oh-my-feed-login`으로 합니다. 설치기는 `PATH`를 바꾸지 않으므로 터미널에서는 `~/.omf/bin/omf`처럼 전체 경로로 실행합니다.

개발 checkout에서 먼저 검증할 때:

```sh
npm run build:cli
node public/cli/install.mjs --source public --prefix /path/to/local-install --scope project --project /path/to/project --client both
```

이전 기본 경로 `~/.local/share/oh-my-feed`를 사용했다면 명시적으로 전환합니다.

```sh
bash -o pipefail -c 'curl -fsS https://ohmyfeed.stream/install.sh | sh -s -- --migrate-legacy'
```

전환은 검증된 개인 상태를 `~/.omf/data`로 복사하고 기존 파일을 남깁니다. 기존 설치기가 만든 것으로 확인되는 스킬·실행 파일만 백업 후 갱신하며, 사용자가 수정한 파일은 덮어쓰지 않습니다. 양쪽 데이터가 다르거나 다른 CLI가 실행 중이면 충돌을 알리고 중단합니다. 자동 업데이트 예약이나 자동 제거는 하지 않습니다.

전환 후에는 `~/.omf/bin/omf`를 사용하세요. 남겨둔 이전 경로와 새 경로가 계속 동기화되지는 않습니다. 설치 프로세스를 강제 종료해 `.install.lock`이 남았다면 실행 중인 설치가 없는지 확인한 뒤 잠금을 정리해야 합니다. 자동으로 오래된 잠금을 삭제하지 않습니다.

## 처음 사용하기

```sh
~/.omf/bin/omf recommend --project . --query 'MCP browser automation'
~/.omf/bin/omf show owner/repository
~/.omf/bin/omf select owner/repository --confirm
~/.omf/bin/omf feedback owner/repository useful --confirm
~/.omf/bin/omf context --json
~/.omf/bin/omf status --json
```

`owner/repository`에는 실제 추천 결과의 ID를 사용합니다. AI에게는 “이 프로젝트에서 브라우저 자동화에 사용할 도구 5개를 추천하고, 근거와 미확인 사항을 함께 알려줘”라고 요청할 수 있습니다. 사용자가 선택하기 전에는 AI가 후보를 저장하거나 승인하지 않습니다. 도구 설치는 별도의 사용자 결정입니다.

사용 패턴은 처음에는 제한적입니다. 명시한 프로젝트의 지원 dependency manifest에서 알려진 기술명을 읽고, 선택·유용함/유용하지 않음 피드백을 후속 추천에 반영합니다. 대화 전체를 이해하는 행동 분석이나 모든 작업을 자동 관측하는 기능은 아닙니다. 결과가 일치 신호 없는 일반 탐색인지도 표시합니다. 넓은 검색어는 점수가 후보를 갈라내지 못합니다 — `변별`이 통과한 후보 수와 마지막 순위와 같은 점수로 탈락한 후보 수를 함께 알려주고, 그럴 때는 `좁히기 후보`로 카탈로그 토픽과 그 빈도를 제시합니다.

추천은 로컬 규칙 매칭이며 품질·보안·라이선스·프로젝트 적합성을 보증하지 않습니다. 본문 출처, 저장소 URL, snapshot 시각과 개별 도구 측정 시각을 확인하세요. 실제 내용 확인은 GitHub 원문에서 이어갑니다.

## 개인정보와 저장

- 프로젝트 신호·선택·피드백·적용 계획·이력은 이 컴퓨터에 저장하며 서비스에 업로드하지 않습니다. 공개 catalog GET 외에 연결된 계정 개인화 읽기·자기 해지 요청을 사용합니다. 공식 출처 검토와 승인된 적용 명령은 계획에 설명한 네트워크 요청을 할 수 있습니다.
- 추천 스캔은 소스코드, `.env`, 토큰, shell history, Codex·Claude 대화 기록을 읽지 않습니다. 알려진 기술명만 뽑고 비공개 패키지 이름과 dependency URL/버전 값은 보관하지 않습니다. 이후 호스트 스킬의 적용 검토는 요청 범위의 실제 로컬 환경·관련 파일과 공식 출처를 별도로 확인합니다.
- CLI 결과를 Codex/Claude에서 읽으면 해당 내용은 기존 AI 도구의 대화에 포함됩니다. 그 도구의 클라우드 처리 정책까지 로컬 전용이라는 뜻은 아닙니다.
- 연결된 CLI는 계정 Saved·관심 주제를 읽지만, Saved를 CLI 선택·실행 승인으로 자동 복사하지 않습니다. guest Saved는 계속 수동으로 계정에 가져옵니다. WebMCP에는 계정 정보를 노출하지 않습니다.
- `--data-dir PATH`로 사용자 상태를 격리할 수 있습니다. `status`에서 상태를 확인하세요. 오프라인에서는 검증된 이전 catalog와 경고를 사용하며 손상된 데이터를 정상으로 간주하지 않습니다.

## 웹 Saved에서 로컬 적용까지

스킬의 기본 순서는 `account-status`, 연결된 경우 `saved`, 이어서 `recommend`입니다. `account-status`는 마지막 `checkedAt`과 `source: "local"`, `remoteChecked: false`를 보여 주는 로컬 관측이며 실시간 권한·해지를 검증하지 않습니다. `saved`·`recommend`·`login`의 원격 조회가 최신 권한을 확인합니다. `login`은 승인 URL 출력·브라우저 승인 대기·연결 완료를 한 CLI 프로세스에서 수행하며, `login --wait`는 명시적 alias, `login --complete`는 중단된 대기의 복구용입니다. 연결되지 않아도 공개 추천은 계속 사용할 수 있습니다. 관심 topic은 최대 3점의 보조 신호로, 프로젝트 직접 일치의 최소 4점보다 약합니다. 추천 품질이나 실제 호환성을 보장하지 않습니다. `saved`는 미등재 ID도 표시합니다.

사용자가 계정 연결을 원할 때 Codex/Claude Code 안에서는 `$oh-my-feed-login`/`/oh-my-feed-login` 스킬을 씁니다. 스킬은 `login --no-wait --json`으로 승인 링크를 먼저 보여 주고, 사용자가 승인했다고 말하면 `login --complete --json`으로 한 번 확인합니다. 터미널에서 직접 연결할 때:

```sh
~/.omf/bin/omf login
# 같은 프로세스가 URL을 출력하고, Google 로그인·기기 코드·30일 읽기 범위 승인 뒤 완료합니다
omf account-status --json
omf saved --limit 5 --offset 0 --json
omf recommend --project . --limit 5 --json
```

`login`은 로컬에서 32바이트 비밀을 만들어 0600 `account.json`에 보관하고 SHA-256 해시만 승인 URL `/account?cliChallenge=<hash>&cliLabel=OMF+CLI`와 코드로 표시합니다. 비밀 원문을 URL·출력·계획에 넣지 않습니다. 웹 방문·Google 로그인만으로 연결을 승인하지 않습니다. pending 10분은 로컬 완료 기한이며 서버가 challenge 생성 시각을 증명하는 것이 아닙니다. OAuth RFC 8628 device flow로 표현하지 않습니다. 완료 전 401은 미승인일 수 있지만 연결 상태의 401은 자격 증명·캐시를 지웁니다. 웹 계정 페이지에서 최대 10개 활성 기기를 조회·해지합니다.

`saved --limit 5 --offset 0 --offline`은 조회 후 24시간 이내이며 30일 grant가 아직 유효한 캐시만 사용하고 stale을 표시합니다. 네트워크 장애에도 같은 제한이 적용됩니다. 원격 해지는 오프라인에서 즉시 확인할 수 없어 캐시가 24시간/남은 grant 기간 중 짧은 기간까지 남을 수 있습니다. `logout --confirm`은 원격 자기 해지와 로컬 삭제이며 `logout --confirm --offline`은 로컬 삭제만 하고 원격 해지 미확인을 알립니다.

후보를 실제 적용하려면 호스트 스킬이 공식 README·설치 문서와 프로젝트 환경을 확인해 JSON 계획을 작성합니다. 사용자에게 정확한 프로젝트, 명령·버전·출처·선행 조건·파일/네트워크/권한 변경·검증·복구를 보여 줍니다. JSON은 `schemaVersion: 1`, `summary`, `compatibility`, `checkedVersion`, `environmentAssessment`, `expectedOutcome`, `sourceUrls`, `prerequisites`, `changes`, `steps`, `verification`, `rollback`, `executionMode: "bounded"`를 사용합니다. 세 증거 필드는 모든 compatibility에서 4096바이트 이하의 비어 있지 않은 문자열이어야 하며, 확인 불가 시 `Unknown: 이유`처럼 명시합니다. `compatibility`는 `supported`, `unsupported`, `needs-input` 중 하나입니다. 단계는 `{id,command,args,timeoutSeconds}`이며 command는 절대 실행 파일 경로, args는 문자열 배열, timeout은 1~120초입니다. 실행·검증 각각 최대 10단계, 계획 최대 64KiB입니다. 비밀을 계획·명령 인자·출력 artifact에 넣지 않습니다.

다음은 기존 Node.js를 확인하고 프로젝트에 예시 파일 하나를 만드는 **규격 예시**입니다. 도구 설치나 live Google 인증을 검증한 예가 아닙니다. `sourceUrls`는 대상 tool ID와 같은 GitHub 저장소의 HTTPS URL이어야 합니다. 예시는 `nodejs/node` 대상이며, 스킬은 실제 공식 출처를 검토하고 로컬 Node 절대 경로·버전·파일 충돌·복구 조건을 확인한 뒤 값을 수정해야 합니다. `unsupported`/`needs-input` 계획은 `steps`와 `verification`을 빈 배열로 둘 수 있지만 승인할 수 없습니다.

This schema example checks an existing Node.js executable and writes one fixture file; it does not install a tool or demonstrate live Google authorization. `sourceUrls` must be HTTPS GitHub URLs under the target repository (`nodejs/node` here). Before proposing it, inspect those sources and replace the executable path/version with verified local values; check that the new file does not already exist. Unsupported or needs-input plans can use empty step/verification arrays and cannot be approved.

```json
{
  "schemaVersion": 1,
  "summary": "Node.js 22.18.0 local fixture; no package installation",
  "compatibility": "supported",
  "checkedVersion": "Verified exact local and documented version: Node.js v22.18.0",
  "environmentAssessment": "macOS or Linux; /usr/local/bin/node reports v22.18.0 and .omf-adoption-example.json does not exist",
  "expectedOutcome": "Both commands exit 0 and .omf-adoption-example.json contains node version v22.18.0",
  "sourceUrls": ["https://github.com/nodejs/node/blob/v22.18.0/README.md"],
  "prerequisites": ["Verify /usr/local/bin/node is the intended v22.18.0 executable", "macOS or Linux; .omf-adoption-example.json must not exist"],
  "changes": ["Create .omf-adoption-example.json in the approved project; no network requests, services or elevated permissions"],
  "steps": [{
    "id": "write-fixture",
    "command": "/usr/local/bin/node",
    "args": ["-e", "const fs=require('node:fs'); if(process.version!=='v22.18.0')process.exit(2); fs.writeFileSync('.omf-adoption-example.json',JSON.stringify({node:process.version}),{flag:'wx',mode:0o600});"],
    "timeoutSeconds": 10
  }],
  "verification": [{
    "id": "verify-fixture",
    "command": "/usr/local/bin/node",
    "args": ["-e", "const fs=require('node:fs'); const value=JSON.parse(fs.readFileSync('.omf-adoption-example.json','utf8')); if(value.node!=='v22.18.0'||process.version!==value.node)process.exit(7);"],
    "timeoutSeconds": 10
  }],
  "rollback": ["After inspecting partial changes and obtaining approval, remove only the newly created .omf-adoption-example.json; do not remove Node.js"],
  "executionMode": "bounded"
}
```

```sh
omf plan OWNER/REPO --file FILE --project . --json
omf plan-show PLAN_ID --project . --json
# 사용자가 위 프로젝트와 digest의 정확한 계획을 실제로 승인한 뒤에만:
omf approve PLAN_ID --digest HASH --confirm --project . --json
omf apply PLAN_ID --digest HASH --confirm --project . --json
omf plans --project . --json
omf plan-show PLAN_ID --project . --json
```

웹 저장·후보 선택·계정 연결·스킬의 제안은 적용 승인이 아닙니다. 스킬이 로그인·grant·계획을 자동 승인해서는 안 됩니다. `--confirm`은 호출자의 승인 확인 표시이며 사람의 동의를 독립적으로 증명하지 않습니다. 계획 digest와 실제 프로젝트 경로가 맞는 승인만 한 번 실행합니다. `shell:false`·제한된 환경·timeout·명령별 stdout+stderr 1MiB 제한을 사용하지만 **sandbox는 아닙니다**. 프로그램은 로컬 사용자 권한으로 동작하며 digest가 다운로드나 실행 파일의 안전성을 보장하지 않습니다. 종료 가능한 foreground 명령만 지원하고 지속 daemon·서비스는 지원하지 않습니다. Windows에서는 실행을 지원하지 않고 계획 조회만 가능합니다.

설정·검증 모두 성공해야 성공입니다. 실제 exit code와 signal·timeout·취소·출력 초과 상태, 검증 receipt를 보관합니다. 원문 출력 대신 byte count/hash를 남깁니다. 실패·중단은 `failed`/`running`으로 남으며 자동 재실행·롤백하지 않습니다. 부분 변경을 검토한 뒤 새 계획과 승인이 필요합니다. 한 승인당 최대 한 번 시작하며 외부 효과의 exactly-once 보장은 아닙니다. 이력은 로컬 `adoptions.json`에 출처·프로젝트·파일 변경 설명과 함께 보관하고 업로드하지 않습니다. 연결 해지·후보 선택 해제·이력 삭제는 설치 파일 제거가 아닙니다. 임시 fixture 검증을 임의 실제 도구 설치 검증으로 일반화하지 않습니다.

## English quick start

With Node.js 22+, run `bash -o pipefail -c 'curl -fsS https://ohmyfeed.stream/install.sh | sh'`. The bootstrap downloads its installer into a private temporary directory and validates the distribution. The executable is `~/.omf/bin/omf`, data is `~/.omf/data`. Standard client skill locations remain unchanged. Restart Codex/Claude Code and invoke `$oh-my-feed` or `/oh-my-feed`. Link an account with `$oh-my-feed-login` or `/oh-my-feed-login`; the installer does not change `PATH`, so a terminal calls `~/.omf/bin/omf` by its full path.

Use `omf recommend --project . --query 'MCP browser automation' --lang en` with the printed executable path. Candidate explanations come from recognized local project technologies and explicit feedback. They are not quality certifications. Use `--json` for agent output; it carries `discrimination` (how far the score separated the shortlist and how many candidates were dropped by the tie-break) and `refinements` (catalog topics that narrow the search, with their counts). Only explicit user choices should call `select ... --confirm` or `feedback ... --confirm`.

Project signals, selections, feedback, source/project files, plans and execution history are not uploaded to OMF. Discovery reads only supported manifests, not source files, secrets, shell history or conversations. Adoption evaluation separately inspects official sources and the specified local environment. Reading output with an AI client subjects that output to the client's existing conversation policy. Optional account linking reads Saved and interests without copying them into local selections or approval. The account/adoption commands here describe the implementation contract, not a production deployment claim.

Start with `omf account-status --json`; if linked, fetch `omf saved --limit 5 --offset 0 --json`, then `omf recommend --project . --limit 5 --json`. Status is a LOCAL observation with the last `checkedAt`, `source: "local"` and `remoteChecked: false`, not a live authorization/revocation check. `saved`, `recommend` and `login` perform the remote read. `login` prints the approval URL, waits for browser approval and completes in one CLI process; `login --wait` is an explicit alias, and `login --complete` is only for an interrupted wait. Unlinked users keep public discovery. Account topics contribute at most 3 points, less than the minimum 4-point direct project match. Scores do not certify quality or compatibility; saved IDs absent from the catalog remain visible as unavailable. `plans` lists summaries; `plan-show` returns the full plan/history.

Only when the user requests linking, run `omf login`. It generates a 32-byte bearer secret locally in a 0600 file and prints only its SHA-256 challenge/code in `/account?cliChallenge=<hash>&cliLabel=OMF+CLI`. The user signs in with Google and explicitly confirms the matching code, device and 30-day read-only personalization scope. The same process completes after approval; `login --wait` is an explicit alias, and `login --complete` is only for an interrupted wait. The 10-minute pending period is a local completion deadline, not server-certified challenge expiry or OAuth RFC 8628. A pending 401 may mean not yet approved; a connected 401 purges credentials/cache. View/revoke up to 10 active devices on the account page. Never approve linking for the user or copy session cookies.

`omf saved --limit 5 --offset 0 --offline` can use stale account data only within 24 hours of retrieval and before grant expiry. Remote revocation cannot be detected offline and may take until that earlier boundary or the next connected 401 to invalidate the cache. `omf logout --confirm` revokes this device and clears local credentials/cache; adding `--offline` clears locally and reports remote revocation unconfirmed.

For adoption, inspect official README/install sources and the actual project environment. Create a secret-free JSON proposal with the schema above. Show the user the exact project and digest, commands, versions, sources, prerequisites, file/network/permission changes, verification and rollback. Run `omf plan OWNER/REPO --file FILE --project . --json` and `omf plan-show PLAN_ID --project . --json`. Only after the user's real approval of that plan run `omf approve PLAN_ID --digest HASH --confirm --project . --json`, then `omf apply PLAN_ID --digest HASH --confirm --project . --json`. Web Saved, selection and account linking are not application approval. `--confirm` records the caller's assertion of approval; it does not independently authenticate human consent.

The runner checks the project path and full digest, launches each approved plan at most once with `shell:false`, and requires successful configuration and verification. It supports bounded foreground commands, not persistent daemons or service starts. Each apply/verification list has at most 10 steps with absolute executables, array arguments and 1–120 second timeouts; a proposal is at most 64KiB and each command has a combined stdout/stderr limit of 1MiB. This is not a sandbox: local-user filesystem/network permissions still apply and a digest does not secure executables or downloads. Windows execution is unsupported; plan inspection remains available.

Inspect actual exit codes, signals, timeouts, cancellation/overflow and verification receipts with `omf plans --project . --json` and `omf plan-show PLAN_ID --project . --json`. Raw stdout/stderr and secrets are not stored; byte counts/hashes are. A failed or interrupted/running plan is not success and must not be retried or rolled back automatically; assess partial changes and request approval for a new plan. This is at-most-once launch, not exactly-once effects. Local `adoptions.json` keeps source URLs, project paths, file-change descriptions and receipts. Unlinking, clearing a selection or deleting history does not uninstall files. Fixture execution is not proof that arbitrary real tools were installed or tested.

## WebMCP 선택적 웹 조회 / Optional site tools

지원되는 브라우저에서 운영 페이지를 열면 AI가 `omf_search_tools`, `omf_get_tool`, `omf_catalog_status`를 사용할 수 있습니다. 도구는 공개 카탈로그만 읽으며 추가 네트워크 조회, 설치, 저장, 계정 접근을 하지 않습니다. CLI의 로컬 프로젝트 분석은 CLI 스킬로 계속 사용합니다.

WebMCP는 호환 브라우저·client·account와 열린 페이지가 필요합니다. 일반 Codex CLI/Claude Code가 자동으로 연결된다고 보장하지 않습니다. 미지원 환경에서는 기존 웹 화면과 CLI가 그대로 동작합니다. [공식 Site tools 안내](https://learn.chatgpt.com/docs/webmcp)

Compatible browsers may expose three read-only catalog tools on the open website. These are optional browser capabilities, not a replacement for local CLI skills or a standard MCP server. No project files, browser Saved state, credentials or account data are exposed. Support depends on the browser/client/account; unsupported browsers continue normally.

For the previous default installation, add `--migrate-legacy` using `sh -s -- --migrate-legacy` in the one-line command. Validated data is copied to `~/.omf/data`; old files remain. Only verified managed artifacts may be replaced with backups. Conflicting data, user-modified skills, or active data locks stop the migration.
