diff --git a/.claude/skills/commit/SKILL.md b/.claude/skills/commit/SKILL.md index 98f1f4af7..7faea2ce5 100644 --- a/.claude/skills/commit/SKILL.md +++ b/.claude/skills/commit/SKILL.md @@ -26,8 +26,8 @@ standard. The format is enforced by `gitlint` in the `commit-msg` hook. ``` 5. Never use `--no-verify`. If pre-commit hooks fail, fix the cause and re-commit. -6. Do not commit secrets, generated artifacts, or work-in-progress to a - protected branch (`main` / `dev` / `master`). +6. Do not commit secrets, generated artifacts, or work-in-progress directly to + the protected `main` branch. ## Types diff --git a/.claude/skills/new-branch/SKILL.md b/.claude/skills/new-branch/SKILL.md index 9750737a5..7ea2c9831 100644 --- a/.claude/skills/new-branch/SKILL.md +++ b/.claude/skills/new-branch/SKILL.md @@ -1,43 +1,44 @@ --- name: new-branch -description: Create a branch following the project's GitFlow Lite model +description: Create a GitHub branch from main with the project naming convention --- # /new-branch -Cut a new branch under the GitFlow Lite model. +Cut a new branch for the GitHub repository. ## Branch model ``` -master = released / stable (tagged on release; protected) -dev = integration branch (protected) -feat/* = cut from dev → PR → merge into dev -fix/* = cut from dev → PR → merge into dev -hotfix/* = cut from master → merge into master AND synced into dev (double merge) -release = dev → master + tag on master (no separate release branch) +main = default and protected branch +feat/* = feature work +fix/* = bug fixes +docs/* = documentation-only changes +ci/* = CI, build, and developer-experience changes +chore/* = repository maintenance +refactor/* = behavior-preserving code structure changes ``` ## Steps -1. Ask (or infer) the change type: `feat`, `fix`, or `hotfix`. -2. Pick the parent: - - `feat/*`, `fix/*` → branch from **`dev`**. - - `hotfix/*` → branch from **`master`**. -3. Update the parent first: +1. Ask (or infer) the change type: `feat`, `fix`, `docs`, `ci`, `chore`, or + `refactor`. +2. Update `main` first: ```bash - git checkout + git checkout main git pull --ff-only ``` -4. Create the branch with a kebab-case slug: +3. Create the branch with a kebab-case slug: ```bash - git checkout -b feat/ + git checkout -b / ``` -5. For a `hotfix`, remember it must later merge into **both** `master` and `dev`. +4. Keep the branch scoped to one purpose and open a pull request back to + `main`. ## Naming -- `feat/add-agentic-rerank`, `fix/empty-profile-crash`, `hotfix/lancedb-conn-leak`. +- `feat/add-agentic-rerank`, `fix/empty-profile-crash`, + `docs/quickstart-config`, `ci/check-github-docs`. - Lowercase, hyphen-separated, no spaces, concise. -Never commit directly to `master` or `dev` — always via a branch + PR. +Never commit directly to `main` — always use a branch and pull request. diff --git a/.claude/skills/pr/SKILL.md b/.claude/skills/pr/SKILL.md index 8a2a7aa32..d24a3217d 100644 --- a/.claude/skills/pr/SKILL.md +++ b/.claude/skills/pr/SKILL.md @@ -10,8 +10,9 @@ Open a pull request on GitHub using the `gh` CLI and the repo's PR template. ## Steps 1. Confirm the branch and target: - - `feat/*`, `fix/*` → base **`dev`**. - - `hotfix/*` → base **`master`** (then a follow-up PR/sync into `dev`). + - Base branch is **`main`**. + - Head branch should be a scoped branch such as `feat/*`, `fix/*`, + `docs/*`, `ci/*`, `chore/*`, or `refactor/*`. 2. Ensure local checks pass first: ```bash make ci @@ -24,7 +25,7 @@ Open a pull request on GitHub using the `gh` CLI and the repo's PR template. 4. Create the PR, filling the template ([.github/PULL_REQUEST_TEMPLATE.md](../../../.github/PULL_REQUEST_TEMPLATE.md)): ```bash - gh pr create --base dev --fill-first + gh pr create --base main --fill-first ``` Then edit the body to complete each section: - **Summary** — what changed and why. @@ -38,4 +39,5 @@ Open a pull request on GitHub using the `gh` CLI and the repo's PR template. - Keep the PR scoped to one area. Split unrelated changes. - If `make ci` was not fully run, say so in Verification rather than implying it passed. -- A `hotfix` is not done until it has landed on **both** `master` and `dev`. +- Never retarget a community PR away from `main` unless a maintainer explicitly + asks for it. diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6f6fa310c..0d2324598 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -7,7 +7,11 @@ on: - ".github/ISSUE_TEMPLATE/**" - ".github/PULL_REQUEST_TEMPLATE.md" - ".github/workflows/docs.yml" + - ".claude/skills/**/*.md" + - "CLAUDE.md" + - "CONTRIBUTING.md" - "scripts/check_docs.py" + - "scripts/check_github_contributor_docs.py" push: branches: [main] paths: @@ -15,7 +19,11 @@ on: - ".github/ISSUE_TEMPLATE/**" - ".github/PULL_REQUEST_TEMPLATE.md" - ".github/workflows/docs.yml" + - ".claude/skills/**/*.md" + - "CLAUDE.md" + - "CONTRIBUTING.md" - "scripts/check_docs.py" + - "scripts/check_github_contributor_docs.py" permissions: contents: read diff --git a/CITATION.md b/CITATION.md index 3db0c9093..2b16b357b 100644 --- a/CITATION.md +++ b/CITATION.md @@ -32,9 +32,9 @@ BibTeX citation information will be added here once the paper is published. To cite the software itself: ``` -EverOS: md-first memory extraction framework for AI agents -Version: 0.1.0 -URL: https://github.com/EverMind-AI/everos +EverOS: local-first memory runtime for AI agents +Version: 1.1.0 +URL: https://github.com/EverMind-AI/EverOS License: Apache 2.0 ``` diff --git a/CLAUDE.md b/CLAUDE.md index 18110ebf0..91d48755b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -47,9 +47,19 @@ Contributor engineering reference — build, test, CI gates, branch & commit con ## Branch strategy -`master` = released stable (hidden); `dev` = integration; `feat/* fix/*` → dev; `hotfix/*` → master + dev (sync). +`main` is the default and protected branch. Create scoped branches from +`main` (`feat/*`, `fix/*`, `docs/*`, `ci/*`, `chore/*`, `refactor/*`) and open +pull requests back to `main` after the required checks pass. -See [.claude/skills/new-branch/SKILL.md](.claude/skills/new-branch/SKILL.md) for the full GitFlow Lite rationale. +See [.claude/skills/new-branch/SKILL.md](.claude/skills/new-branch/SKILL.md) +for the full branch workflow. + +## GitHub sync guard + +When refreshing this repository from an internal source archive, preserve +GitHub-only contributor and automation files. Do not overwrite `CLAUDE.md`, +`.claude/skills/*`, `CONTRIBUTING.md`, or `.github/*` workflow/template files +without checking [docs/github-sync.md](docs/github-sync.md). ## Storage three-piece set diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index defeb22cf..6cfd24f8b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,7 +91,7 @@ internally. git clone https://github.com/EverMind-AI/EverOS.git cd EverOS make install # deps + pre-commit hooks (one-stop dev setup) -everos init # write ./.env, then fill in the API key slots +everos init # write ~/.everos/everos.toml + ome.toml make ci # verify: lint + unit + integration + package ``` @@ -153,7 +153,7 @@ Full conventions: [.claude/rules/testing.md](.claude/rules/testing.md). - `/new-branch` — create branch with proper naming - `/commit` — generate a Conventional Commits message -- `/pr` — internal merge request with correct target branch +- `/pr` — open a GitHub pull request with the correct target branch --- diff --git a/Makefile b/Makefile index d6f633a99..338f749ea 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help install install-deps lint docs-check check-commits check-pr-title check-assets check-deprecated-names check-cjk check-datetime openapi check-openapi format test integration package cov ci clean +.PHONY: help install install-deps lint docs-check check-commits check-pr-title check-assets check-deprecated-names check-github-docs check-cjk check-datetime openapi check-openapi format test integration package cov ci clean help: @echo "Targets:" @@ -10,6 +10,7 @@ help: @echo " check-pr-title Validate PR title uses Conventional Commit format" @echo " check-assets Block committed images, videos, and asset/media directories" @echo " check-deprecated-names Block deprecated product names" + @echo " check-github-docs Block legacy/internal branch-model residue in contributor docs" @echo " check-cjk Scan for CJK outside the language-policy allowlist (advisory)" @echo " check-datetime Scan for code that bypasses component/utils/datetime (HARD gate, run via lint)" @echo " openapi Regenerate docs/openapi.json from the FastAPI app" @@ -39,11 +40,13 @@ lint: uv run lint-imports uv run python scripts/check_repo_assets.py uv run python scripts/check_deprecated_names.py + uv run python scripts/check_github_contributor_docs.py uv run python scripts/check_datetime_discipline.py uv run python scripts/dump_openapi.py --check docs-check: python3 scripts/check_docs.py + python3 scripts/check_github_contributor_docs.py ruby -e 'require "yaml"; Dir[".github/ISSUE_TEMPLATE/*.yml"].sort.each { |p| YAML.load_file(p); puts "YAML ok: #{p}" }' check-commits: @@ -61,6 +64,11 @@ check-assets: check-deprecated-names: uv run python scripts/check_deprecated_names.py +# GitHub contributor-doc gate. Public contribution guidance must target the +# GitHub `main` workflow, not an internal branch model. +check-github-docs: + uv run python scripts/check_github_contributor_docs.py + # Advisory CJK scan (see .claude/rules/language-policy.md). Deliberately NOT # wired into `lint` / `ci`: the policy is enforced by review and the rules # doc, not a hard gate. Run on demand when touching potentially-CJK files. diff --git a/QUICKSTART.md b/QUICKSTART.md index dfd19f140..250dfde43 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -10,15 +10,19 @@ front of your agent. ## Prerequisites - **Python 3.12+** -- **An OpenRouter API key** — covers the chat LLM (memory extraction) - *and* the multimodal LLM (parsing image / pdf / audio content items) - with a single key. -- **A DeepInfra API key** — for the embedding + rerank models that - OpenRouter doesn't ship. - -Two keys total. Any OpenAI-compatible endpoint plugs in via the -matching `*__BASE_URL` env var if you'd rather use OpenAI directly, -self-host vLLM, route to Ollama, etc. +- **An LLM provider key and endpoint** — for memory extraction. OpenRouter, + OpenAI, and other OpenAI-compatible providers work when you set + `base_url`. +- **A multimodal provider key and endpoint** — needed only when parsing + image / pdf / audio content items. +- **Embedding and rerank provider keys and endpoints** — for search. DeepInfra + works for the embedding + rerank path; vLLM and DashScope are also supported + for rerank. + +Many deployments use two distinct keys by reusing one LLM key for `[llm]` and +`[multimodal]`, and one DeepInfra key for `[embedding]` and `[rerank]`. Any +setting can live in TOML or be overridden by the matching `EVEROS_*` +environment variable. ## 1. Install @@ -29,15 +33,15 @@ pip install everos ## 2. Configure -Generate the starter config and drop in your two keys: +Generate the starter config and fill in provider credentials: ```bash everos init # writes ~/.everos/everos.toml + ome.toml (use --root to relocate) -# Edit ~/.everos/everos.toml and fill four api_key slots (only two distinct keys needed): -# [llm] api_key (OpenRouter — chat LLM) -# [multimodal] api_key (OpenRouter — same key works) -# [embedding] api_key (DeepInfra) -# [rerank] api_key (DeepInfra — same key works) +# Edit ~/.everos/everos.toml and fill the provider fields: +# [llm] api_key + base_url (chat LLM) +# [multimodal] api_key + base_url (optional parser LLM) +# [embedding] model + api_key + base_url +# [rerank] model + api_key + base_url (provider can be inferred or set) ``` `everos init` generates two files: `everos.toml` (provider settings) @@ -48,9 +52,9 @@ after editing: `chmod 600 ~/.everos/everos.toml`. The shipped template sets model defaults for `[llm]` (`gpt-4.1-mini`) and `[multimodal]` (`google/gemini-3-flash-preview`); `[embedding]` and `[rerank]` ship no model default — set `model` + `base_url` for those two -sections yourself (e.g. DeepInfra's `Qwen/Qwen3-Embedding-4B` / -`Qwen/Qwen3-Reranker-4B`). To use a different OpenAI-compatible endpoint -for any provider, set the matching `base_url` field. +sections yourself (for example DeepInfra's `Qwen/Qwen3-Embedding-4B` / +`Qwen/Qwen3-Reranker-4B`). `[llm]` and `[multimodal]` ship model defaults, +but still need `api_key` and `base_url` before those capabilities are used. > **Where config lives** — `everos init` writes into the memory root > (`~/.everos` by default; relocate with `everos init --root ` and diff --git a/SECURITY.md b/SECURITY.md index 60f6e22e3..487c8fd8a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Supported Versions -EverOS is released and at v1.0.0 (stable). Security fixes are applied to the +EverOS is released and in the v1.x stable line. Security fixes are applied to the latest release line only. | Version | Supported | @@ -39,8 +39,9 @@ following in mind: is loopback-only. Only set the bind to `0.0.0.0` (or any routable interface) after you have placed your own gateway / auth layer in front; `everos server start` will log a warning when you bind to `0.0.0.0`. -- Secrets (LLM / embedding API keys) live in your local `.env`; protect that - file as you would any credential. EverOS never transmits them anywhere except - the providers you configure. +- Secrets (LLM / embedding / rerank API keys) normally live in your local + `/everos.toml`, or in `EVEROS_*` environment variables for container + deployments. Protect those values as you would any credential. EverOS never + transmits them anywhere except the providers you configure. - Memory content is stored as plaintext `.md` files; apply OS-level file permissions or disk encryption if your data is sensitive. diff --git a/docs/configuration.md b/docs/configuration.md index eda0f4964..22e2c4cde 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -105,7 +105,7 @@ everos init --root /data/everos |---|---|---|---|---| | `model` | string | `"gpt-4.1-mini"` | No | LLM model identifier. | | `api_key` | string | — | **Yes** | API key for the LLM provider. | -| `base_url` | string | — | No | Custom endpoint URL (OpenAI-compatible). | +| `base_url` | string | — | **Yes** | Endpoint URL (OpenAI-compatible). | ### `[multimodal]` @@ -113,7 +113,7 @@ everos init --root /data/everos |---|---|---|---|---| | `model` | string | `"google/gemini-3-flash-preview"` | No | Multimodal parsing model. | | `api_key` | string | — | **Yes** | API key. | -| `base_url` | string | — | No | Custom endpoint URL. | +| `base_url` | string | — | **Yes** | Endpoint URL. | | `max_concurrency` | int | `4` | No | Max parallel parsing requests. | | `file_uri_allow_dirs` | list[string] | `[]` | No | Allowlisted base dirs for `file://` URIs. Empty = allow any readable file. | | `file_uri_max_bytes` | int | `52428800` | No | Max size (bytes) of a `file://` asset; larger files are rejected. | @@ -134,7 +134,7 @@ everos init --root /data/everos | Field | Type | Default | Required | Description | |---|---|---|---|---| -| `provider` | string | `"deepinfra"` | No | Rerank provider: `deepinfra` or `vllm`. | +| `provider` | string | inferred | No | Rerank provider: `deepinfra`, `vllm`, or `dashscope`. | | `model` | string | — | **Yes** | Reranker model identifier. | | `api_key` | string | — | **Yes** | API key. | | `base_url` | string | — | **Yes** | Rerank endpoint URL. | @@ -210,9 +210,13 @@ variables directly: ENV EVEROS_ROOT=/data/everos ENV EVEROS_LLM__API_KEY=sk-... ENV EVEROS_LLM__MODEL=gpt-4o +ENV EVEROS_LLM__BASE_URL=https://api.openai.com/v1 ENV EVEROS_EMBEDDING__MODEL=text-embedding-3-large ENV EVEROS_EMBEDDING__API_KEY=sk-... ENV EVEROS_EMBEDDING__BASE_URL=https://api.openai.com/v1 +ENV EVEROS_RERANK__MODEL=Qwen/Qwen3-Reranker-4B +ENV EVEROS_RERANK__API_KEY=... +ENV EVEROS_RERANK__BASE_URL=https://api.deepinfra.com/v1/inference ENV EVEROS_API__HOST=0.0.0.0 ENV EVEROS_API__PORT=8000 ``` diff --git a/docs/github-sync.md b/docs/github-sync.md new file mode 100644 index 000000000..3a2aa9cc3 --- /dev/null +++ b/docs/github-sync.md @@ -0,0 +1,77 @@ +# GitHub Sync Guard + +This page records the GitHub-only files that must be preserved when refreshing +this public repository from the internal GitLab source/export. + +## Rule + +When a GitLab export, archive, rsync, or scripted copy is used to refresh the +GitHub repository, do **not** blindly overwrite GitHub-only contributor, +automation, and public-facing workflow files. + +These files describe the public GitHub workflow: protected `main`, scoped +branches, GitHub pull requests, GitHub Actions, and community contribution +rules. Internal workflow text can mislead contributors and AI coding tools if +it is copied into GitHub. + +## Preserve These GitHub Files + +Keep the GitHub versions of these files unless a maintainer deliberately updates +them for the public GitHub workflow: + +- `CLAUDE.md` +- `CONTRIBUTING.md` +- `.github/PULL_REQUEST_TEMPLATE.md` +- `.github/BRANCH_PROTECTION.md` +- `.github/workflows/ci.yml` +- `.github/workflows/docs.yml` +- `.github/workflows/commits.yml` +- `.github/ISSUE_TEMPLATE/**` +- `.claude/skills/commit/SKILL.md` +- `.claude/skills/new-branch/SKILL.md` +- `.claude/skills/pr/SKILL.md` +- `scripts/check_github_contributor_docs.py` +- `tests/unit/test_scripts/test_check_github_contributor_docs.py` + +## Safe Sync Pattern + +Prefer an explicit exclude list in the sync job rather than manual cleanup after +the overwrite. Example shape: + +```bash +rsync -a --delete \ + --exclude 'CLAUDE.md' \ + --exclude 'CONTRIBUTING.md' \ + --exclude '.github/PULL_REQUEST_TEMPLATE.md' \ + --exclude '.github/BRANCH_PROTECTION.md' \ + --exclude '.github/workflows/ci.yml' \ + --exclude '.github/workflows/docs.yml' \ + --exclude '.github/workflows/commits.yml' \ + --exclude '.github/ISSUE_TEMPLATE/' \ + --exclude '.claude/skills/commit/SKILL.md' \ + --exclude '.claude/skills/new-branch/SKILL.md' \ + --exclude '.claude/skills/pr/SKILL.md' \ + --exclude 'scripts/check_github_contributor_docs.py' \ + --exclude 'tests/unit/test_scripts/test_check_github_contributor_docs.py' \ + / / +``` + +After any sync, run: + +```bash +make docs-check +make lint +``` + +The `check_github_contributor_docs.py` gate catches the known failure mode: +public contributor docs drifting back to an internal branch/review model. + +## Review Checklist + +Before opening a sync PR: + +- Confirm `CLAUDE.md` says branches are created from `main`. +- Confirm `.claude/skills/pr/SKILL.md` creates PRs with `--base main`. +- Confirm `CONTRIBUTING.md` says GitHub pull request, not internal review + terminology. +- Confirm `make docs-check` and `make lint` both pass. diff --git a/docs/index.md b/docs/index.md index 3b5935275..367df8cd3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -50,6 +50,7 @@ specific thing (drain a queue, recover from a stuck row, etc.). | Doc | Purpose | |---|---| | [cascade_runbook.md](cascade_runbook.md) | Cascade subsystem ops — drain queue, recover stuck rows | +| [github-sync.md](github-sync.md) | Guardrails for refreshing GitHub from internal exports without overwriting GitHub-only workflow files | | [locomo_benchmark.md](locomo_benchmark.md) | LoCoMo benchmark — run and evaluate | ## Engineering diff --git a/docs/use-cases.md b/docs/use-cases.md index 05d015d33..aa31dcbd7 100644 --- a/docs/use-cases.md +++ b/docs/use-cases.md @@ -147,7 +147,7 @@ Ruminer brings persistent memory to a browser agent so it can carry personal con #### EverMem Sync with EverOS -One command to connect any AI coding CLI to EverMemOS long-term memory. +One command to connect any AI coding CLI to EverOS long-term memory. [Code](https://github.com/nanxingw/EverMem) diff --git a/scripts/check_github_contributor_docs.py b/scripts/check_github_contributor_docs.py new file mode 100644 index 000000000..3a500c3d1 --- /dev/null +++ b/scripts/check_github_contributor_docs.py @@ -0,0 +1,133 @@ +"""Block legacy/internal branch-model residue in contributor guidance docs.""" + +from __future__ import annotations + +import re +from collections.abc import Iterable +from dataclasses import dataclass +from pathlib import Path + +MONITORED_FILES = ( + Path("CLAUDE.md"), + Path("CONTRIBUTING.md"), + Path("docs/engineering.md"), + Path(".github/PULL_REQUEST_TEMPLATE.md"), + Path(".claude/skills/commit/SKILL.md"), + Path(".claude/skills/new-branch/SKILL.md"), + Path(".claude/skills/pr/SKILL.md"), +) + +BRANCH_WORKFLOW_FILES = frozenset( + { + Path("CLAUDE.md"), + Path(".claude/skills/commit/SKILL.md"), + Path(".claude/skills/new-branch/SKILL.md"), + Path(".claude/skills/pr/SKILL.md"), + } +) + + +@dataclass(frozen=True) +class Rule: + label: str + pattern: re.Pattern[str] + paths: frozenset[Path] | None = None + + +@dataclass(frozen=True) +class Violation: + path: Path + line_number: int + label: str + text: str + + +_LEGACY_HOSTING = "git" + "lab" +_LEGACY_STABLE_BRANCH = "mas" + "ter" +_LEGACY_INTEGRATION_BRANCH = "de" + "v" +_LEGACY_EMERGENCY_BRANCH = "hot" + "fix" +_LEGACY_BRANCH_MODEL = "git" + "flow" + +RULES = ( + Rule( + "legacy hosting reference", + re.compile(rf"\b{_LEGACY_HOSTING}\b", re.IGNORECASE), + ), + Rule( + "legacy review wording", + re.compile(r"\bmerge\s+request\b", re.IGNORECASE), + ), + Rule( + "legacy branch model", + re.compile(rf"\b{_LEGACY_BRANCH_MODEL}\b", re.IGNORECASE), + ), + Rule( + "legacy stable branch reference", + re.compile(rf"\b{_LEGACY_STABLE_BRANCH}\b", re.IGNORECASE), + ), + Rule( + "legacy integration branch reference", + re.compile( + rf"(? list[Violation]: + violations: list[Violation] = [] + for path, text in file_texts: + for line_number, line in enumerate(text.splitlines(), start=1): + for rule in RULES: + if rule.paths is not None and path not in rule.paths: + continue + if rule.pattern.search(line): + violations.append( + Violation( + path=path, + line_number=line_number, + label=rule.label, + text=line.strip(), + ) + ) + return violations + + +def _read_monitored_files() -> list[tuple[Path, str]]: + return [ + (path, path.read_text(encoding="utf-8")) + for path in MONITORED_FILES + if path.exists() + ] + + +def main() -> int: + violations = find_violations(_read_monitored_files()) + if not violations: + print("GitHub contributor-doc check passed.") + return 0 + + print( + "GitHub contributor-doc check failed.\n" + "These files should describe the public GitHub workflow: protected " + "`main`, scoped branches, and pull requests back to `main`.\n" + ) + for violation in violations: + print( + f"- {violation.path}:{violation.line_number}: " + f"{violation.label}: {violation.text}" + ) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/everos/config/default.toml b/src/everos/config/default.toml index d96a439d6..ad9bf7b58 100644 --- a/src/everos/config/default.toml +++ b/src/everos/config/default.toml @@ -131,6 +131,14 @@ vector_strategy = "maxsim_atomic" # requires a restart. Override via EVEROS_MEMORIZE__MODE. mode = "agent" +# Maximum wall-clock for one memorize() invocation while holding the +# per-session lock. On timeout the outer asyncio.timeout cancels the call +# and the lock auto-releases so subsequent concurrent /add on the same +# session aren't deadlocked. Covers boundary LLM + memcell writes + +# synchronous portion of pipeline dispatch. +# Override via EVEROS_MEMORIZE__SESSION_LOCK_TIMEOUT_SECONDS. +session_lock_timeout_seconds = 360.0 + [knowledge] # Max bytes for an uploaded knowledge document (default 50 MiB). Oversized # uploads are rejected with HTTP 422 before parsing/extraction. Note: the @@ -147,14 +155,6 @@ lambda = 0.1 mass_top_m = 50 top_k_cap = 100 -# Maximum wall-clock for one memorize() invocation while holding the -# per-session lock. On timeout the outer asyncio.timeout cancels the call -# and the lock auto-releases so subsequent concurrent /add on the same -# session aren't deadlocked. Covers boundary LLM + memcell writes + -# synchronous portion of pipeline dispatch. -# Override via EVEROS_MEMORIZE__SESSION_LOCK_TIMEOUT_SECONDS. -session_lock_timeout_seconds = 360.0 - [clustering] # Geometry-clustering: cosine similarity threshold and time window. # Episodes older than ``time_window_days`` from the newest cluster diff --git a/tests/unit/test_scripts/test_check_github_contributor_docs.py b/tests/unit/test_scripts/test_check_github_contributor_docs.py new file mode 100644 index 000000000..0cc0b4704 --- /dev/null +++ b/tests/unit/test_scripts/test_check_github_contributor_docs.py @@ -0,0 +1,74 @@ +"""Self-tests for ``scripts/check_github_contributor_docs.py``.""" + +from __future__ import annotations + +import importlib.util +import sys +from pathlib import Path + +_REPO_ROOT = Path(__file__).resolve().parents[3] +_CHECKER_PATH = _REPO_ROOT / "scripts" / "check_github_contributor_docs.py" + + +def _load_checker(): + assert _CHECKER_PATH.exists(), "GitHub contributor-doc checker should exist" + spec = importlib.util.spec_from_file_location( + "_github_contributor_docs_checker", _CHECKER_PATH + ) + assert spec and spec.loader + mod = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = mod + spec.loader.exec_module(mod) + return mod + + +def test_clean_github_workflow_is_allowed() -> None: + checker = _load_checker() + + violations = checker.find_violations( + [ + ( + Path("CLAUDE.md"), + "Create scoped branches from main and open pull requests.\n", + ) + ] + ) + + assert violations == [] + + +def test_legacy_branch_model_terms_are_blocked() -> None: + checker = _load_checker() + stable_branch = "mas" + "ter" + integration_branch = "de" + "v" + legacy_review = "merge " + "request" + branch_model = "Git" + "Flow" + emergency_branch = "hot" + "fix" + + violations = checker.find_violations( + [ + ( + Path("CLAUDE.md"), + f"{stable_branch} is stable and {integration_branch} is integration.\n", + ), + (Path("CONTRIBUTING.md"), f"Open an internal {legacy_review}.\n"), + ( + Path(".claude/skills/pr/SKILL.md"), + f"{branch_model} {emergency_branch} path.\n", + ), + ] + ) + + assert [(v.path.as_posix(), v.label) for v in violations] == [ + ("CLAUDE.md", "legacy stable branch reference"), + ("CLAUDE.md", "legacy integration branch reference"), + ("CONTRIBUTING.md", "legacy review wording"), + (".claude/skills/pr/SKILL.md", "legacy branch model"), + (".claude/skills/pr/SKILL.md", "legacy emergency branch model"), + ] + + +def test_real_repo_has_no_legacy_contributor_doc_residue() -> None: + checker = _load_checker() + + assert checker.main() == 0