This is the counterpart of create_project: it is for a repo that already
exists, while create_project scaffolds a brand-new one.
`repo_full_name` is "owner/repo". Import requires that the SAME caller
listed the repository with list_github_repos() within the last 10 minutes,
OR that the workspace already holds a valid repository grant. An absent or
expired authorization returns code `repository_access_required`; call
list_github_repos() again, then retry. Missing, expired, foreign and
nonexistent repositories share that same generic denial, so the tool never
reveals whether a guessed repository exists.
`engine` is OPTIONAL — one of claude_code | codex | glm | kimi | grok
(defaults to claude_code); codex/glm/kimi/grok require a matching connected
credential.
`build_description` is OPTIONAL but STRONGLY recommended — a plain-language
"what should Keelen build first?" submitted as the project's first Request so
the loop has work; an imported project with no Request sits idle until
submit_request(project_id, ...) adds one.
`project_kind` is OPTIONAL — one of library | node_library | python_library |
service | cli | web_app | godot_game | roblox_game | mobile_app | unknown.
Omit it and the kind is auto-detected. It is required for a MONOREPO (apps in
subdirectories), a stack with no standard root manifest (Java, Ruby, PHP,
.NET, Elixir), or a classification detection cannot infer — detection yields
"unknown" there, which BLOCKS the dev lane until
someone overrides it. A supplied value is authoritative and is never
overwritten by later auto-detection. `stack` is the OPTIONAL language axis
(python | node | rust | go | cpp) for a language-agnostic kind.
`preview_command` is REQUIRED when project_kind is "web_app" (the command
that serves the app locally, e.g. "npm run dev") and optional otherwise,
where it overrides the detected one.
A root **Expo** repository imports as `mobile_app` under a conservative,
Expo-only contract. Recognition requires a root `package.json` declaring
both `expo` and `react-native` plus root Expo config evidence, resolved in
documented precedence order (first present wins): dynamic app.config.ts,
app.config.mts, app.config.cts, app.config.mjs, app.config.cjs,
app.config.js by FILENAME PRESENCE only, then static app.config.json, then
app.json. Imported config is inspected as data and never executed; a nested
config, config-free Expo package, ordinary Node package, or unreadable root
probe does not qualify — unreadable evidence stays `unknown` instead of
manufacturing a mobile result. Mobile is a Node toolchain whose automated
QA is the detected `test_command`; it has no preview command and therefore
no browser or native verification. This recognition phase is Expo-only:
mobile creation is unavailable until R2 (`create_project` refuses
`mobile_app` with `mobile_creation_unsupported`), and browser activation,
export readiness and native verification are outside this item. When
detection cannot qualify the repository, pass `project_kind: "mobile_app"`
(optionally `stack: "node"`) yourself; a supplied pick is authoritative
and preserved against later auto-detection. Picking the kind derives the
`test_command` QA default — a kind-derived default, not explicit QA
ownership; explicit QA ownership is a deliberate test-command choice in the
dashboard QA setup.
Re-importing the same live repo is replay-guarded (returns the existing
project with already_exists=True), and re-importing a SOFT-DELETED repo
RESTORES that deleted row in place — it does not create a fresh project.
Restored queued work can include refinement that deletes tasks, and the call
is not idempotent end to end. On a plan with no scheduled-project allowance
the project is still created but with the loop OFF — next_step then names
get_billing(). Otherwise next_step names the poll of
get_provisioning_status(project_id).