Agent Skills
› psyray/oasis
› oasis-python-architecture
oasis-python-architecture
GitHub定义OASIS Python项目的模块布局、职责划分及DRY原则,规范orchestration、analysis、LLM输出处理等核心逻辑的目录结构与导入纪律。
Trigger Scenarios
编辑oasis/下的Python文件
添加共享工具或契约
Install
npx skills add psyray/oasis --skill oasis-python-architecture -g -y
SKILL.md
Frontmatter
{
"name": "oasis-python-architecture",
"description": "Python module layout and centralization rules for OASIS. Use when editing any Python file under oasis\/ (oasis.py, analyze.py, backends\/, report.py, web.py, agent\/, schemas\/, structured_output\/, export\/, helpers\/) or when adding shared utilities, progress\/report wire contracts, model-backend contracts, or CLI flags."
}
OASIS Python Architecture
- No duplicated logic (non-negotiable): Never copy-paste or parallel-implement the same behavior in two places. If something exists twice (even slightly divergent), stop and consolidate: one canonical implementation, callers import or delegate to it. This is mandatory DRY; KISS applies to the solution, not to skipping extraction. SOLID implies a single place per responsibility—duplication always violates that.
- Centralize by default: Shared constants, validation rules, formatters, parsers, JSON/report field naming, URL or path rules, and error messages belong in one module each (
oasis/helpers/,oasis/schemas/, or another existing shared module)—not redefined ad hoc in multiple files. - Keep responsibilities split by module: orchestration in
oasis/oasis.py, analysis inoasis/analyze.py, structured schemas inoasis/schemas/, structured LLM output normalization / JSON repair inoasis/structured_output/(deep.py,json_repair.py,json_repair_scan.py), canonical JSON + Jinja report rendering inoasis/report.py, export writers (Markdown/HTML/PDF/SARIF) inoasis/export/, dashboard indexing inoasis/web.py, model-backend lifecycle inoasis/backends/(see below);oasis/ollama_manager.pyis a backward-compat shim only. - LangGraph (
oasis/agent/): The compiled DAG (graph.py), state (state.py), stable node/route identifiers (graph_labels.py), andinvoke_oasis_langgraph(invoke.py) own orchestration structure. Node bodies dispatch toSecurityAnalyzermethods inanalyze.pyviatools.py/nodes.py— keep business logic inanalyze.pyand keep the graph layer a thin wiring + state pass-through. The assistant validation subgraph (assistant_graph.py,assistant_labels.py,assistant_nodes.py,assistant_state.py,assistant_invoke.py) routes on vulnerability family (flow→ entry_points → trace → taint → mitigations → verdict;access→ entry_points → authz → verdict;config→ config_audit → verdict) and follows the same lazy-import discipline. Use explicit imports from submodules (e.g.oasis.agent.invoke) so importingoasis.agentdoes not eagerly load LangGraph unless needed. - Analysis type:
AnalysisType.GRAPHis the only scan/deep orchestration mode; chunk caches use LangGraph paths only (oasis/cache.py). - Model backends (
oasis/backends/):base.ModelBackendis the provider-agnostic contract — chat /chat_stream/generatenormalize responses to the Ollama shape ({"message": {"content": ...}}), and model listing, interactive selection, thinking overrides, and chunk-size detection live in the base.ollama_backend.OllamaManagerkeeps the Ollama-specific machinery (auto-pull,ps()runtime context,show()metadata,think=).openai_compat.OpenAICompatManager+OpenAICompatClientserve OpenAI-compatible servers (vLLM, LM Studio, llama.cpp, LiteLLM, …) via httpx while exposing ollama-shaped client methods (embeddings(model=, prompt=),list()), translatingoptions.num_predict→max_tokens,format=<json_schema>→response_formatwith an automatic schema-in-prompt retry on HTTP 4xx (OASIS_OPENAI_STRUCTURED_OUTPUT), and reading context windows fromOASIS_OPENAI_CTX_TOKENS. The factorycreate_model_manager(backends/__init__.py) resolves--provider→OASIS_LLM_PROVIDER→ auto-detect, and multiprocessing worker namespaces carryprovider/api_base/api_key. Never branch on the provider at call sites (analyze.py,embedding.py,web.py) — extend the backend contract instead;oasis/ollama_manager.pyis a compat shim only. Tests:tests/test_backends_openai_compat.py. - LangGraph-related helpers:
oasis/helpers/langgraph_cli/bundles CLI banners/emits, debug separators, LLM debug logging, and LangGraph vuln-type count helpers.oasis/helpers/progress/includes graph pipeline rows (graph_pipeline_phases,graph_progress_extras, …), tqdm/coercion, executive-summary phase extras, and scan progress JSON/markdown helpers.oasis/helpers/context/expand.pyholdsexpand_line_window/expand_suspicious_chunk_records(CONTEXT_EXPAND_*inoasis/config.py).oasis/helpers/poc/covers PoC digest JSON, hints markdown, and PoC stage logging options.oasis/helpers/ollama_timing/holds Ollama payload size / timeout helpers for logging. - Embedding model normalization: Parse and normalize CLI embedding model values through
oasis/helpers/embedding/(normalize_embed_models,resolve_embed_models,primary_embed_model,resolve_valid_embedding_input_files) and keep one canonical source for model-list parsing and primary-model fallback. Invalid input raisesEmbedModelValueError(subclass ofValueError);oasis/oasis.pymaps that toargparse.ArgumentTypeErroronly inargparsetype=callables. - Helpers (
oasis/helpers/): All reusable utilities that behave like helpers must live underoasis/helpers/, not inlined in feature modules (analyze.py,report.py,web.py, etc.). If you add or refactor something that is formatting, parsing, small pure transforms, progress/status builders, shared guards, or other cross-cutting non–entry-point utilities, move it intooasis/helpers/as part of the change. - Helper categories (thematic subpackages under
oasis/helpers/):dashboard/—audit_metrics,report_preview_html,dashboard_links,severity_filter, main__init__(formats, Socket.IO/CORS, phase cells) andexec_summary_tiers(tiers; safe for earlyconfigimport).phases/—scan(phase rows, adaptive/standard phase lists).progress/— tqdm, coercion, LangGraph pipeline extras, scan progress markdown (EXEC_SUMMARY_PROGRESS_EVENT_VERSION,SCAN_PROGRESS_EXTENDED_KEYSat top ofoasis/helpers/progress/__init__.py).embedding/,langgraph_cli/,poc/,ollama_timing/,prompt_compose/,cli_update/.context/—expand,path_containment(safe paths undersecurity_reports).vuln/—taxonomy,validation_patterns.executive/— assistant scope, dashboard preview, modal chart metadata.report_project.py— project slug / output dir naming;analysis_root_path.py— canonical resolution of JSONanalysis_root(relative undersecurity_reports/vs legacy absolute).executive_summary.py— executive canonical JSON + HTML view models.misc.pyat package root (snippets + structured-output degeneracy);naming.py(shared naming rules) andreport_jinja_filters.py(Jinja filters for report templates) sit at package root as well;lazy_export_validation.pybacks the lazy-export contract (test_helpers_lazy_exports/test_helpers_lazy_subpackage_exportsguard__all__vs_LAZY_IMPORTS). Dashboard assistant underoasis/helpers/assistant/(scan,authz,verdict,prompt,web,think). Theweb/subpackage groups HTTP-orchestration helpers used byoasis/web.py:web_prepare.py(chat context preparation),sink_resolution.py(resolve(sink_file, sink_line)from finding indices +finding_scope_report_path;coerce_positive_int_linefor numeric coercion),result_presentation.py(post-verdict EP / citation filter forflow+accessfamilies anchored onscope.sink_file; never mutates verdict),http_contract.py,rag.py,persistence.py,api_validate.py. Do not duplicate sink resolution or EP filtering logic insideweb.py— call these helpers.schemas/audit_report.py— structured audit document beside Markdown.oasis/helpers/__init__.pyuses lazy exports (test_helpers_lazy_exportsguards__all__vs_LAZY_IMPORTS). - Report output layout: New scans default to
security_reports/<project_slug>/…; CLI--project-name/-pnoverrides slug derivation. Keepoasis/helpers/report_project.py, export writers, and dashboard indexing rules aligned when layout or metadata fields change. - Canonical JSON
analysis_root: New reports store the scanned tree relative tosecurity_reports/; useoasis/helpers/analysis_root_path.pyfor resolution (integrations, assistant RAG cache root,scan_rootcandidates)—do not fork second resolution logic inweb.pyor the assistant. - Package surface: Export the intended public helper API from
oasis/helpers/__init__.pywhen symbols are meant for use outside the package; keep imports stable and explicit. - Incremental scan progress (wire contract):
- Constants (top of
oasis/helpers/progress/__init__.py):EXEC_SUMMARY_PROGRESS_EVENT_VERSIONbumps when the incremental progress payload is no longer backward-compatible for consumers (web.py, dashboard); extendSCAN_PROGRESS_EXTENDED_KEYSwhen new optional fields must pass throughpublish_incremental_summaryand the executive-summary sidecar. Unknown keys are stripped there—keep the allowlist andReport._append_scan_progress_sectionaligned; contract coverage includestests/test_report_schema.py(e.g. stripping unknown extras). - Timestamps: Use
progress_timestamp_iso()inoasis/report.pyforupdated_at. Do not change the ISO-8601 shape without updating the dashboard stale guard inoasis/static/js/dashboard/api.js(lexicographic compare of UTC strings). - Sidecar: Persist incremental progress beside the executive summary JSON using
executive_summary_progress_sidecar_pathonly—do not invent parallel path rules. - Helper roles:
oasis/helpers/phases/scan.py(phase row builders and TypedDict wire shapes).oasis/helpers/progress/(tqdm lifecycle, coercion, standard/adaptive extras, scan progress markdown helpers, LangGraph graph row builders).oasis/helpers/dashboard/(parse_phase_counts_from_progress_cellfor markdown table cells). - Audit markdown metrics contract: If
oasis/report.pychanges the## Audit Metrics Summarymarkdown table (Metric | Valuerows), keepoasis/helpers/dashboard/audit_metrics.pyandoasis/web.pyaggregation aligned so dashboard audit comparison remains backward-compatible. - Phase row status strings: Canonical values live in
oasis/enums.py(PhaseRowStatus). Emit those wire strings from Python; the dashboard mirrors them as string constants only. - Graph pipeline rows: LangGraph runs use
graph_progress_extras/graph_pipeline_phasesinoasis/helpers/progress/withProgressPhaseRowId.GRAPH_DISCOVER…GRAPH_VERIFY. When changing phase ids, labels, or ordering, alignprogress/, any callers inanalyze.py, and dashboard consumers if the wire shape changes.
- Constants (top of
- Favor small manager/service classes over monolithic procedural flows when adding features.
- Preserve CLI backward compatibility when possible (short and long flags); if a rename is required, mirror it in docs.
- For docs touched by behavior changes, keep
README.mdFeaturessummary-only and place detailed behavior/usage in the relevant dedicated section (create one for new feature areas). - Keep
CHANGELOG.mdentries concise, style-consistent, and filed under the version bucket that matches current branch lineage. - Open-source hygiene: examples in code, help strings, docstrings, and tests use neutral placeholders (
https://llm.example.com/v1) — never personal infrastructure details (hostnames, SSH aliases, keys, container names); such documentation lives in the uncommitted workspace mirror, not in the repo. - Route logs through centralized project logging helpers; avoid ad-hoc print statements in production paths.
- For resilience changes (cache, network/model calls), prefer defensive fallbacks and explicit error handling.
- Tests: Integration-style checks live under
tests/astest_<area>.pyfiles aligned with product modules (report contract intests/test_report_schema.py, CLI intests/test_oasis_cli.py, LangGraph orchestration intests/test_analyze_orchestration.py, embedding pure helpers intests/test_embedding_pure.py, dashboard helpers intests/test_helpers_dashboard.py, model backends/providers intests/test_backends_openai_compat.py, etc.). When you change behavior covered by those areas, update or add tests in the matching file rather than skipping coverage for new branches.
Version History
- ed3afbb Current 2026-09-11 14:59


