name: build-paths-beginner description: Scaffold a small RAG chatbot on Oracle 26ai Free + langchain-oracledb + OCI Generative AI Grok 4 + sentence-transformers MiniLM-L6-v2 (Python-side embeddings, same model intermediate/advanced register inside Oracle) + Open WebUI. Three flavors that share one skeleton — PDF / Markdown / Web. For users new to Oracle who want a polished demo running in an afternoon. inputs: - target_dir: where to scaffold (default = current working directory; ask if it isn't empty) - topic: optional; one of beginner/project-ideas.md, or a free-text pitch
The user picked the beginner path. Your job is to interview them, scaffold a working project that ingests a corpus and exposes a Grok-4-powered chat UI in Open WebUI, run verify, and stop. The output is a real shippable mini-product, not a tutorial.
Step 0 — Read these references first (mandatory)
shared/references/sources.mdshared/references/oracle-26ai-free-docker.mdshared/references/langchain-oracledb.md← load-bearingshared/references/oci-genai-openai.md← load-bearing (Pattern 1 SigV1 auth)shared/references/oracledb-python.md(skim — beginner only touchesoracledb.connect)shared/references/exemplars.mdbeginner/project-ideas.mdskills/oracle-aidb-docker-setup/SKILL.md— you'll invoke thisskills/langchain-oracledb-helper/SKILL.md— you'll invoke this
You may not write SQL, embedder calls, or table-creation code that contradicts these files. If the user asks for something not covered, say so and stop — don't invent.
Step 1 — Interview
Run the questions from shared/interview.md. For beginner specifically:
- Q3 (DB target) — default to "Local Docker" without re-asking.
- Q4 (Inference) — not optional anymore at this tier. OCI Generative AI for the LLM (Grok 4 via bearer-token). MiniLM Python-side for embeddings. Verify:
OCI_GENAI_API_KEY(ask-...value) is set in the user's shell env OR about to be written into the project's.env. If neither, stop and ask the user to generate one in the OCI GenAI service console.- The user is OK with non-zero OCI cost (mention this once — Grok 4 is not on the always-free list).
- Default endpoint is
https://inference.generativeai.us-phoenix-1.oci.oraclecloud.com; the user can override viaOCI_GENAI_BASE_URLif their key is region-locked elsewhere. - Embedder:
sentence-transformers/all-MiniLM-L6-v2(384 dim) by default — runs inside the user's Python process viaHuggingFaceEmbeddings. Same model that intermediate/advanced register inside Oracle, so corpus + chunks stay comparable across tiers. - Chat:
xai.grok-4(full id required —grok-4alone won't resolve).
- Q5 (Topic) — pick one of the three from
beginner/project-ideas.md. Map free-text pitches to the closest. If none fits, default to idea 1 (PDFs) and tell the user why. - Q6 (Notebook) — default no. Beginner ships the chat UI, not a notebook walkthrough.
Print the confirmation block from interview.md. Don't proceed without an explicit y.
Step 2 — Resolve choices
Build a scaffold spec from the interview:
| Variable | Value |
|---|---|
project_slug |
derived from topic, kebab-case: pdf-chat, notes-chat, web-chat |
package_slug |
snake_case: pdf_chat, notes_chat, web_chat |
target_dir |
from Q2; default = current working directory. Never assume a host-specific layout. |
embedder |
minilm-py (always) |
embedding_dim |
384 |
embedding_model_id |
sentence-transformers/all-MiniLM-L6-v2 |
llm_model |
grok-4 (or fallback chosen during interview) |
oci_base_url |
https://inference.generativeai.us-phoenix-1.oci.oraclecloud.com (the OpenAI client appends /v1; do not add the legacy /20231130/actions/openai path — that is for SigV1, not bearer-token) |
collections |
["DOCUMENTS", "CONVERSATIONS"] |
has_chat_history |
True |
ingest_module |
ingest.py for PDFs/markdown, add.py for web pages |
entrypoint |
python -m <package_slug>.adapter (FastAPI on :8000); Open WebUI on :3000 talks to it |
Step 3 — Scaffold
Order matters — invocation of building-block skills happens before project code.
3a — Foundation via building-block skills
- Refuse if
target_diris non-empty. - Invoke
skills/oracle-aidb-docker-setup. Passtarget_dir. It writesdocker-compose.yml(Oracle),.env(with generatedORACLE_PWD), brings the container up healthy. Block until it reports OK. - Append the Open WebUI service to the generated
docker-compose.yml:open-webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui ports: - "127.0.0.1:3000:8080" environment: - OPENAI_API_BASE_URL=http://host.docker.internal:8000/v1 - OPENAI_API_KEY=local-stub-key - WEBUI_AUTH=False extra_hosts: - "host.docker.internal:host-gateway" volumes: - openwebui_data:/app/backend/data volumes: openwebui_data: - Invoke
skills/langchain-oracledb-helper. Passtarget_dir,package_slug,embedder=minilm-py,collections=["DOCUMENTS", "CONVERSATIONS"],has_chat_history=True. It writesstore.py,_monkeypatch.py,history.py,migrations/001_chat_history.sql. The helper will installsentence-transformersand pre-cache the model on first import to avoid a stall during the first user query. Block until it reports OK.
3b — Project-specific code (the only files this skill writes itself)
target_dir/.gitignore— extend withdata/,*.pdf,notes/.target_dir/pyproject.toml— extend deps:- Always:
fastapi>=0.110,uvicorn[standard]>=0.27,langchain-core>=0.3,langchain-community>=0.3,openai>=1.40,langchain-huggingface>=0.1,sentence-transformers>=2.7. - Idea 1 (PDFs): +
pypdf>=4. - Idea 2 (Markdown): +
markdown-it-py>=3. - Idea 3 (Web): +
trafilatura>=1.10,httpx>=0.27. - Do NOT add
oci-openaioropenai— friction P0-2; the OpenAI-compat path is unstable. The chat factory atshared/snippets/oci_chat_factory.pyuses the direct OCI SDK.
- Always:
target_dir/.env.example— append:
ConfirmOCI_GENAI_API_KEY=replace_me_sk_value_from_oci_genai_console OCI_GENAI_BASE_URL=https://inference.generativeai.us-phoenix-1.oci.oraclecloud.com OCI_LLM_MODEL=xai.grok-4 EMBED_MODEL=sentence-transformers/all-MiniLM-L6-v2target_dir/.gitignorecontains.env(the docker-setup skill adds it). Never commitOCI_GENAI_API_KEY.src/<package_slug>/inference.py— copyshared/snippets/oci_chat_factory.py(chat — uses the direct OCI SDK, model idxai.grok-4). For the embedder, write a tiny factory:
Cite the OCI factory at the top.from langchain_huggingface import HuggingFaceEmbeddings _embedder = None def get_embedder(): global _embedder if _embedder is None: _embedder = HuggingFaceEmbeddings(model_name=os.environ["EMBED_MODEL"]) return _embeddersrc/<package_slug>/<ingest_module>— per idea:- Idea 1: walk
data/pdfs/, parse viapypdf, chunk by page + 800-token windows,store.get_store("DOCUMENTS").add_texts(...)withmetadata={"filename": ..., "page": ...}. Idempotent — keep adata/.ingested.jsonledger. - Idea 2: walk
NOTES_DIR, chunk by H2 sections viamarkdown-it-py, metadata ={"path": ..., "heading": ..., "frontmatter": {...}}. - Idea 3:
python -m web_chat.add URL—trafilatura.fetch_url+extract, chunk, metadata ={"url": ..., "title": ..., "fetched_at": ..., "byline": ...}.
- Idea 1: walk
src/<package_slug>/chain.py— LCEL chain: retriever (get_store("DOCUMENTS").as_retriever(k=5)) → prompt with citation instructions →ChatOpenAI-shaped LLM via OCI. Wrap withRunnableWithMessageHistory(chain, get_history_factory(get_connection()), input_messages_key="question", history_messages_key="history"). Citation format depends on idea (filename:page / file#heading / URL).src/<package_slug>/adapter.py— FastAPI app exposing/v1/chat/completions(OpenAI-compatible). Body shape matches what Open WebUI sends; mapmessages[-1].contentto the chain input, return assistant message in OpenAI shape. Stream viatext/event-stream.verify.py— copyshared/templates/verify.template.py, fill in:inference_enabled = True.- Round-trip:
embedder.embed_query("dim check")→ assert dim == 384. - Smoke a single chain call against a tiny known corpus (3 lines of test text).
README.md— copyshared/templates/readme.template.md, fill placeholders. The "Why Oracle" paragraph names: AI Vector Search,OracleVS, persistent chat history (OracleChatHistory). Include a "Stack" section listing OCI GenAI Grok 4,sentence-transformers/all-MiniLM-L6-v2(Python-side, 384 dim — same model intermediate/advanced register inside Oracle for in-DB embeddings),langchain-oracledb, Open WebUI. Leave the screenshot slot for the chat UI.
Step 4 — Verify
- The DB is already up (skill 1 ensured this).
- From
target_dir:python -m venv .venv && source .venv/bin/activate && python -m pip install -e .. python verify.py. Expectverify: OK (db, vector, inference). The vector check assertslen(get_embedder().embed_query("dim check")) == 384. First run downloads the MiniLM weights (~90MB) — note this in the verify output so the user knows what's happening. On failure: followshared/verify.mdrecovery loop, max 3 retries.- Bring Open WebUI up:
docker compose up -d open-webui. Wait ~10s. - Run the adapter in the background:
python -m <package_slug>.adapter(port 8000). Hithttp://localhost:8000/v1/models— should return JSON listing one model. Then checkhttp://localhost:3000responds (Open WebUI loaded). - Don't keep the adapter running — just confirm it boots cleanly. Kill it before reporting done.
Step 5 — Polish for sharing
- README — confirm all placeholders are filled.
docs/— leave a note: "drop a 30s demo GIF asdocs/demo.gifshowing PDF drop → ingest → chat".- Final report:
Done. project at: <target_dir> run with: cd <target_dir> docker compose up -d python -m <package_slug>.<ingest_module> <args> python -m <package_slug>.adapter # blocks; Open WebUI on :3000 verify: OK ui: http://localhost:3000 (Open WebUI) adapter: http://localhost:8000/v1/chat/completions next: drop your corpus, run ingest, record a 30s demo, push to GitHub.
Stop conditions
~/.oci/configmissing — stop, point atoci setup config.- User explicitly refuses to use OCI GenAI (cost concern, no tenancy). Tell them this tier requires it; offer to point them at the archive's old Ollama-flavored beginner ideas if they want.
- Verify fails 3 times.
- Target dir non-empty.
- The user picks a non-Oracle DB or non-Python language. Print "out of scope for v1" and stop.
When to graduate to OAMP
If you grow this beginner project into a multi-user app — different humans hitting the same backend, each wanting their own preferences and durable facts remembered across sessions — swap the manual OracleChatHistory layer for OAMP (oracleagentmemory PyPI package). OAMP gives you per-user threads, automatic memory extraction, and prompt-ready context cards out of the box, and the advanced tier already wires it for you. See shared/references/oamp.md for the decision tree (OAMP vs. OracleVS vs. OracleChatHistory vs. plain SQL). Until then, stay on OracleChatHistory — single-user, full transcript visibility, no LLM-extraction cost.
What you must NOT do
- Don't write raw
CREATE TABLE ... VECTOR(...)DDL —OracleVS.from_texts(via the helper skill's bootstrap dance) handles it. - Don't introduce Gradio, Streamlit, Flask, or any non-Open-WebUI frontend. Open WebUI + FastAPI adapter is the contract.
- Don't introduce Redis, Postgres, ChromaDB, FAISS, or any non-Oracle store — even as a fallback.
- Don't introduce Ollama as a fallback. Earlier versions of this tier supported it; the new tier is OCI-only on purpose. If the user can't use OCI, point them at
archive/beginner-ideas.md. - Don't write more than ~450 lines of project code total. If you're going past that, stop and reduce.
- Don't generate
ORACLE_PWDyourself — the helper skill does it. - Don't claim done before verify is green AND the adapter boots cleanly.