translate the system prompt constant and the user-message template in
backend/app/services/ontology_generator.py from chinese to english.
the chinese base prompt was biasing the model toward chinese structure
and word choice even when accept-language was en, leaving ontology
descriptions and analysis_summary fields chinese-flavoured.
translation is in-place and preserves every functional contract: the
json output schema, the entity-type and relationship-type taxonomies
verbatim, the reserved-attribute-name list, the count and length
constraints, and all f-string interpolations. the
get_language_instruction() postfix call site and the trailing english
identifier-format directive are unchanged, so zh and other locales
continue to receive locale-appropriate descriptions.
logger calls, docstrings, and inline comments are intentionally left
in chinese — they are owned by issues #6 and #7.
a small static guard script (backend/scripts/test_ontology_prompts_no_cjk.py)
ast-parses the module and asserts zero cjk in the system prompt and in
every string literal of _build_user_message except the docstring, so
the regression cannot reappear silently.
Closes#2
Adds a Neo4j service to docker-compose so `docker compose up -d` works
on a clean checkout, and unhardcodes Graphiti's LLM/embedder so the
documented default provider (Qwen via Dashscope) actually works.
- docker-compose: neo4j:5-community service with cypher-shell
healthcheck, named volumes, and `depends_on: service_healthy` on the
app container; in-Docker NEO4J_URI override leaves the host-mode
default untouched.
- Config: new GRAPHITI_LLM_PROVIDER (openai|gemini, default openai) plus
optional EMBEDDING_API_KEY / EMBEDDING_BASE_URL that fall back to the
chat LLM credentials.
- graphiti_adapter: provider switch inside the singleton factory with
lazy per-provider imports; Gemini path is preserved exactly. The
no-op `_GeminiReranker` becomes a provider-agnostic
`_PassthroughReranker`, still injected explicitly so Graphiti does
not fall back to its OpenAI-only default reranker.
- Drop the ignored `reranker=` kwarg from `_GraphNamespace.search` and
the misleading callers in `zep_tools.py` and
`oasis_profile_generator.py`.
- Refresh `.env.example` to mirror the README env section.
Spec, requirements, and design under
`.kiro/specs/graphiti-neo4j-finalize/`.
Closes#1
Add .kiro/steering/ as persistent project memory for CC-SDD / Kiro
workflows. Three core files (product, tech, structure) capture
purpose, stack, and organization patterns; three custom files
(database, api-standards, error-handling) pin the load-bearing
project-specific conventions:
- group_id isolation and the Graphiti adapter / event-loop singleton
- {success, data|error} envelope and the Task polling contract
- reasoning-model output stripping and the retry_with_backoff helper
Files focus on patterns and decisions, not catalogs, per the
steering-principles "golden rule".
Adopt CC-SDD (Kiro) as the project's spec-driven planning tool, with
plans persisted in .kiro/specs/ and a checkpoint after every task
(strictest cadence — no code without an approved plan).
CC-SDD install (via npx cc-sdd@latest --claude --lang en):
- .kiro/settings/rules/: EARS format, gap-analysis, design and
requirements review gates, design discovery, tasks generation,
steering principles, parallel-task analysis.
- .kiro/settings/templates/: specs (init, requirements, design, tasks,
research) and steering (product/tech/structure plus optional
api-standards/auth/db/deployment/error-handling/security/testing).
- .claude/commands/kiro/: 11 Kiro slash commands — spec-init,
spec-requirements, spec-design, spec-tasks, spec-impl, spec-status,
steering, steering-custom, validate-gap, validate-design,
validate-impl.
Local additions:
- .claude/commands/plan.md: /plan [task] wrapper that picks up the task
from $ARGUMENTS or a single .ticket/<n>.md snapshot, walks the Kiro
flow (steering -> spec-init -> spec-requirements -> validate-gap ->
spec-design -> validate-design -> spec-tasks) and stops for human
approval after each artefact. Refuses "just code it" requests.
- .claude/hooks/session_start.sh: extend to print active tickets
(.ticket/*.md) and open specs (.kiro/specs/*/) with phase from
spec.json, alongside the existing branch/state line.
Documentation: .claude/onboarding/step4_workflow/01_tool_decision.md
Adapt the Notion onboarding prompt — originally Jira/MCP-oriented — to
this project's actual issue tracker (GitHub at
salestech-group/MiroFish) using the gh CLI.
Slash commands (.claude/commands/):
- /ticket <number>: fetch a GitHub issue via gh, self-assign, try to
add an in-progress label (skips silently if the label doesn't exist),
and snapshot the issue (frontmatter + body) to .ticket/<n>.md so
later planning steps can read the description without refetching.
- /ticket-list: interactive overview of issues; asks for filters
(open/closed, status, assignee, milestone, labels) and runs a single
gh issue list with the answers, rendering a compact markdown table.
Workspace:
- .ticket/repo.md declares the target repo (GitHub equivalent of the
Jira "board.md" referenced in the prompt).
- .gitignore: ignore .ticket/* except repo.md and .gitkeep so cached
ticket markdowns stay local.
Settings:
- Allow-list gh issue view/list/edit/comment, gh repo view,
gh pr view/list, gh auth status to avoid permission prompts.
Documentation: .claude/onboarding/step3_planning/01_ticket_sync.md
Permissions:
- Allow npm run/test/install, uv run/sync, docker (compose), and the
common read-only/staging git commands so routine work doesn't trigger
permission prompts.
- Deny Read/Write/Edit on uploads/ and .codegraph/ (auto-generated and
user-data paths) in addition to the existing .env*/secrets/ blocks.
Hooks:
- SessionStart: print branch, ahead/behind vs upstream, and working-tree
state at session start so context is visible immediately.
- PreToolUse (Read|Write|Edit|Bash|NotebookEdit): defence-in-depth
guard that intercepts attempts to access .env / secrets/ paths (and
bash commands targeting them) with a friendly, logged refusal on top
of the permissions.deny rules.
PostToolUse formatter is intentionally skipped — the project has no
configured formatter (per the Step 1 conventions decision).
The Stop hook (quality gate) will be configured in Step 6.
Documentation: .claude/onboarding/step2_setup/01_settings_analysis.md
Bring repo docs in line with the Graphiti+Neo4j migration and prepare
the codebase for Spec-Driven Development.
CLAUDE.md:
- Promote Neo4j + Graphiti to primary memory/graph layer; mark Zep
Cloud as deprecated / compat-only.
- Document the full env-var surface: NEO4J_*, EMBEDDING_MODEL, optional
LLM_BOOST_* block.
- Codify must-respect implementation rules (Task model for long ops,
reasoning-output stripping, simulation IPC, subprocess cleanup,
startup recovery, per-project group_id isolation, chat prefix
injection).
- Note i18n (vue-i18n + /locales/) and Docker prerequisite for dev.
README.md / README-EN.md / README-ZH.md:
- Resolve unresolved merge-conflict markers in README.md left over from
the feat/graphiti-neo4j-migration merge (file was broken Markdown).
- Lead with Docker as the recommended deployment path; keep source
install as a documented alternative.
- Replace Zep env vars with NEO4J_URI / NEO4J_USER / NEO4J_PASSWORD /
EMBEDDING_MODEL across all three READMEs.
- Add optional LLM_BOOST_* block with omit-if-unused note.
- Fix language-switcher links between the three READMEs.
.claude/onboarding/step1_codebase/:
- Document repo analysis, CLAUDE.md conventions decisions, and README
resolution choices.
- Add sans-serif font for English left-pane (status, workflow sections)
- Shorten English workflow step descriptions
- Reduce English report title font-size from 36px to 28px
- Use sans-serif font for English titles, descriptions and navbar
- Shorten English hero text to avoid overflow
- Fix :global() scoped CSS issue that was setting root font-size to 3.5rem
- Use separate unscoped style block for html[lang] selectors
Background threads (graph building, simulation prep, report generation,
profile generation) now inherit the requesting user's locale preference.
Previously these fell back to 'zh' because Flask request context was
unavailable in spawned threads.
Ensure poster_type stays PascalCase English and stance stays English enum
values regardless of language setting. Only natural language fields follow
the user's language preference.
The language instruction was causing LLM to change entity/relation naming
conventions. Now explicitly enforce PascalCase/UPPER_SNAKE_CASE for technical
identifiers while only applying language preference to description fields.