gossamer-web 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. gossamer_web-0.9.0/.coderadar.toml +37 -0
  2. gossamer_web-0.9.0/.github/workflows/ci.yml +120 -0
  3. gossamer_web-0.9.0/.github/workflows/release.yml +160 -0
  4. gossamer_web-0.9.0/.gitignore +54 -0
  5. gossamer_web-0.9.0/AGENTS.md +23 -0
  6. gossamer_web-0.9.0/CHANGELOG.md +1203 -0
  7. gossamer_web-0.9.0/CONTRIBUTING.md +64 -0
  8. gossamer_web-0.9.0/Cargo.lock +3196 -0
  9. gossamer_web-0.9.0/Cargo.toml +40 -0
  10. gossamer_web-0.9.0/LICENSE +194 -0
  11. gossamer_web-0.9.0/PKG-INFO +249 -0
  12. gossamer_web-0.9.0/README.md +204 -0
  13. gossamer_web-0.9.0/SECURITY.md +53 -0
  14. gossamer_web-0.9.0/benchmarks.py +399 -0
  15. gossamer_web-0.9.0/docs/ARCHITECTURE.md +356 -0
  16. gossamer_web-0.9.0/docs/QUICKREF.md +67 -0
  17. gossamer_web-0.9.0/gossamer/__init__.py +157 -0
  18. gossamer_web-0.9.0/gossamer/_core.pyi +860 -0
  19. gossamer_web-0.9.0/gossamer/agent_tools.py +1259 -0
  20. gossamer_web-0.9.0/gossamer/budget.py +138 -0
  21. gossamer_web-0.9.0/gossamer/cache.py +468 -0
  22. gossamer_web-0.9.0/gossamer/citations.py +336 -0
  23. gossamer_web-0.9.0/gossamer/cli.py +187 -0
  24. gossamer_web-0.9.0/gossamer/config.py +700 -0
  25. gossamer_web-0.9.0/gossamer/crawl.py +981 -0
  26. gossamer_web-0.9.0/gossamer/dedup.py +110 -0
  27. gossamer_web-0.9.0/gossamer/discovery.py +251 -0
  28. gossamer_web-0.9.0/gossamer/document.py +1158 -0
  29. gossamer_web-0.9.0/gossamer/env.py +86 -0
  30. gossamer_web-0.9.0/gossamer/fetch.py +1336 -0
  31. gossamer_web-0.9.0/gossamer/guard.py +561 -0
  32. gossamer_web-0.9.0/gossamer/keystore.py +138 -0
  33. gossamer_web-0.9.0/gossamer/liveness.py +153 -0
  34. gossamer_web-0.9.0/gossamer/mcp_server.py +311 -0
  35. gossamer_web-0.9.0/gossamer/meta_extractor.py +232 -0
  36. gossamer_web-0.9.0/gossamer/models.py +408 -0
  37. gossamer_web-0.9.0/gossamer/py.typed +0 -0
  38. gossamer_web-0.9.0/gossamer/research_categories.py +508 -0
  39. gossamer_web-0.9.0/gossamer/research_providers.py +3055 -0
  40. gossamer_web-0.9.0/gossamer/resource_store.py +330 -0
  41. gossamer_web-0.9.0/gossamer/robots.py +212 -0
  42. gossamer_web-0.9.0/gossamer/search.py +419 -0
  43. gossamer_web-0.9.0/gossamer/search_providers.py +830 -0
  44. gossamer_web-0.9.0/gossamer/sections.py +35 -0
  45. gossamer_web-0.9.0/gossamer/settings.py +255 -0
  46. gossamer_web-0.9.0/gossamer/ssrf.py +75 -0
  47. gossamer_web-0.9.0/gossamer/structured_parser.py +894 -0
  48. gossamer_web-0.9.0/gossamer/text_links.py +59 -0
  49. gossamer_web-0.9.0/gossamer/thesaurus.json +36 -0
  50. gossamer_web-0.9.0/gossamer/token_budget.py +276 -0
  51. gossamer_web-0.9.0/pyproject.toml +100 -0
  52. gossamer_web-0.9.0/requirements.txt +13 -0
  53. gossamer_web-0.9.0/scripts/audit_cargo.py +94 -0
  54. gossamer_web-0.9.0/skills/gossamer/SKILL.md +67 -0
  55. gossamer_web-0.9.0/src/adapters.rs +7548 -0
  56. gossamer_web-0.9.0/src/budget.rs +392 -0
  57. gossamer_web-0.9.0/src/cacheutils.rs +173 -0
  58. gossamer_web-0.9.0/src/categories.rs +149 -0
  59. gossamer_web-0.9.0/src/cite.rs +1037 -0
  60. gossamer_web-0.9.0/src/dedupe.rs +201 -0
  61. gossamer_web-0.9.0/src/guard.rs +325 -0
  62. gossamer_web-0.9.0/src/lib.rs +1643 -0
  63. gossamer_web-0.9.0/src/metaextract.rs +469 -0
  64. gossamer_web-0.9.0/src/miscutils.rs +310 -0
  65. gossamer_web-0.9.0/src/pycompat.rs +154 -0
  66. gossamer_web-0.9.0/src/robots.rs +313 -0
  67. gossamer_web-0.9.0/src/sections.rs +405 -0
  68. gossamer_web-0.9.0/src/ssrf.rs +380 -0
  69. gossamer_web-0.9.0/src/textlinks.rs +80 -0
  70. gossamer_web-0.9.0/src/tokens.rs +295 -0
  71. gossamer_web-0.9.0/src/urls.rs +581 -0
  72. gossamer_web-0.9.0/src/xmlatom.rs +236 -0
  73. gossamer_web-0.9.0/tests/conftest.py +198 -0
  74. gossamer_web-0.9.0/tests/fixtures/guard_corpus/README.md +20 -0
  75. gossamer_web-0.9.0/tests/fixtures/guard_corpus/benign/01_library_docs.md +25 -0
  76. gossamer_web-0.9.0/tests/fixtures/guard_corpus/benign/02_release_notes.md +24 -0
  77. gossamer_web-0.9.0/tests/fixtures/guard_corpus/benign/03_prompt_engineering_article.md +24 -0
  78. gossamer_web-0.9.0/tests/fixtures/guard_corpus/benign/04_forum_thread.md +23 -0
  79. gossamer_web-0.9.0/tests/fixtures/guard_corpus/benign/05_product_page.md +24 -0
  80. gossamer_web-0.9.0/tests/fixtures/guard_corpus/injected/01_hidden_comment.md +15 -0
  81. gossamer_web-0.9.0/tests/fixtures/guard_corpus/injected/02_fake_system_turn.md +17 -0
  82. gossamer_web-0.9.0/tests/fixtures/guard_corpus/injected/03_polite_request.md +15 -0
  83. gossamer_web-0.9.0/tests/fixtures/guard_corpus/injected/04_exfiltration.md +17 -0
  84. gossamer_web-0.9.0/tests/fixtures/guard_corpus/injected/05_tool_redirection.md +13 -0
  85. gossamer_web-0.9.0/tests/fixtures_mini.pdf +51 -0
  86. gossamer_web-0.9.0/tests/test_browser_integration.py +30 -0
  87. gossamer_web-0.9.0/tests/test_browser_provider.py +133 -0
  88. gossamer_web-0.9.0/tests/test_c1_follow_links.py +110 -0
  89. gossamer_web-0.9.0/tests/test_c2_metadata.py +152 -0
  90. gossamer_web-0.9.0/tests/test_c3_retry.py +170 -0
  91. gossamer_web-0.9.0/tests/test_c4_doc_cache_truncation.py +59 -0
  92. gossamer_web-0.9.0/tests/test_c5_structured_links.py +123 -0
  93. gossamer_web-0.9.0/tests/test_c6_batch_cache.py +168 -0
  94. gossamer_web-0.9.0/tests/test_cache.py +328 -0
  95. gossamer_web-0.9.0/tests/test_citations.py +373 -0
  96. gossamer_web-0.9.0/tests/test_cli.py +74 -0
  97. gossamer_web-0.9.0/tests/test_crawler.py +833 -0
  98. gossamer_web-0.9.0/tests/test_dedup_liveness.py +317 -0
  99. gossamer_web-0.9.0/tests/test_doc_images.py +150 -0
  100. gossamer_web-0.9.0/tests/test_doc_size_cap.py +94 -0
  101. gossamer_web-0.9.0/tests/test_exa_provider_features.py +240 -0
  102. gossamer_web-0.9.0/tests/test_extract_links.py +172 -0
  103. gossamer_web-0.9.0/tests/test_fix_bare_filename.py +73 -0
  104. gossamer_web-0.9.0/tests/test_fix_batch_metadata.py +123 -0
  105. gossamer_web-0.9.0/tests/test_fix_guard_bench.py +105 -0
  106. gossamer_web-0.9.0/tests/test_fix_json_integrity.py +145 -0
  107. gossamer_web-0.9.0/tests/test_fix_provider_fallback.py +90 -0
  108. gossamer_web-0.9.0/tests/test_fix_setext_sections.py +127 -0
  109. gossamer_web-0.9.0/tests/test_fix_url_error_contract.py +140 -0
  110. gossamer_web-0.9.0/tests/test_focused_discovery.py +456 -0
  111. gossamer_web-0.9.0/tests/test_focused_discovery_semantic.py +612 -0
  112. gossamer_web-0.9.0/tests/test_guard.py +699 -0
  113. gossamer_web-0.9.0/tests/test_html_store.py +101 -0
  114. gossamer_web-0.9.0/tests/test_input_shapes.py +254 -0
  115. gossamer_web-0.9.0/tests/test_live_smoke.py +407 -0
  116. gossamer_web-0.9.0/tests/test_m10_batch_error.py +134 -0
  117. gossamer_web-0.9.0/tests/test_m11_budget_loop.py +113 -0
  118. gossamer_web-0.9.0/tests/test_m12_markdown_links.py +136 -0
  119. gossamer_web-0.9.0/tests/test_m13_rate_limit_copy.py +53 -0
  120. gossamer_web-0.9.0/tests/test_m14_looks_like_text.py +47 -0
  121. gossamer_web-0.9.0/tests/test_m15_retry_after.py +133 -0
  122. gossamer_web-0.9.0/tests/test_m16_document_formats.py +109 -0
  123. gossamer_web-0.9.0/tests/test_m17_fetch_mode_dispatch.py +250 -0
  124. gossamer_web-0.9.0/tests/test_m1_local_paths.py +81 -0
  125. gossamer_web-0.9.0/tests/test_m2_provider_aliases.py +141 -0
  126. gossamer_web-0.9.0/tests/test_m3_retry.py +129 -0
  127. gossamer_web-0.9.0/tests/test_m4_truncate_fallback.py +69 -0
  128. gossamer_web-0.9.0/tests/test_m5_encoding.py +65 -0
  129. gossamer_web-0.9.0/tests/test_m6_asyncio.py +95 -0
  130. gossamer_web-0.9.0/tests/test_m7_bounded_state.py +107 -0
  131. gossamer_web-0.9.0/tests/test_m8_use_smart.py +185 -0
  132. gossamer_web-0.9.0/tests/test_m9_http_pool.py +118 -0
  133. gossamer_web-0.9.0/tests/test_mcp_server.py +178 -0
  134. gossamer_web-0.9.0/tests/test_meta_oxide.py +254 -0
  135. gossamer_web-0.9.0/tests/test_p2_doc_extra.py +73 -0
  136. gossamer_web-0.9.0/tests/test_p8_tool_registry.py +148 -0
  137. gossamer_web-0.9.0/tests/test_p9_doc_store.py +195 -0
  138. gossamer_web-0.9.0/tests/test_patent_adapters.py +171 -0
  139. gossamer_web-0.9.0/tests/test_phase3_adapters.py +457 -0
  140. gossamer_web-0.9.0/tests/test_phase3_wave2.py +415 -0
  141. gossamer_web-0.9.0/tests/test_plan_fixes.py +485 -0
  142. gossamer_web-0.9.0/tests/test_providers.py +278 -0
  143. gossamer_web-0.9.0/tests/test_research_categories.py +639 -0
  144. gossamer_web-0.9.0/tests/test_research_providers.py +732 -0
  145. gossamer_web-0.9.0/tests/test_resource_store.py +139 -0
  146. gossamer_web-0.9.0/tests/test_rust_parity_adapters.py +5560 -0
  147. gossamer_web-0.9.0/tests/test_rust_parity_budget.py +206 -0
  148. gossamer_web-0.9.0/tests/test_rust_parity_categories.py +94 -0
  149. gossamer_web-0.9.0/tests/test_rust_parity_citations.py +456 -0
  150. gossamer_web-0.9.0/tests/test_rust_parity_dedupe.py +198 -0
  151. gossamer_web-0.9.0/tests/test_rust_parity_guard.py +319 -0
  152. gossamer_web-0.9.0/tests/test_rust_parity_metaextract.py +242 -0
  153. gossamer_web-0.9.0/tests/test_rust_parity_robots.py +215 -0
  154. gossamer_web-0.9.0/tests/test_rust_parity_sections.py +275 -0
  155. gossamer_web-0.9.0/tests/test_rust_parity_ssrf.py +262 -0
  156. gossamer_web-0.9.0/tests/test_rust_parity_tokens.py +196 -0
  157. gossamer_web-0.9.0/tests/test_rust_parity_urls.py +262 -0
  158. gossamer_web-0.9.0/tests/test_s1_ssrf.py +232 -0
  159. gossamer_web-0.9.0/tests/test_s2_hidden.py +164 -0
  160. gossamer_web-0.9.0/tests/test_s3_size_cap.py +178 -0
  161. gossamer_web-0.9.0/tests/test_s4_robots.py +281 -0
  162. gossamer_web-0.9.0/tests/test_s5_concurrency.py +307 -0
  163. gossamer_web-0.9.0/tests/test_s6_scoped_clear.py +87 -0
  164. gossamer_web-0.9.0/tests/test_s7_disk_key.py +34 -0
  165. gossamer_web-0.9.0/tests/test_s7_fetch_politeness.py +129 -0
  166. gossamer_web-0.9.0/tests/test_search_provider_defaults.py +90 -0
  167. gossamer_web-0.9.0/tests/test_settings.py +188 -0
  168. gossamer_web-0.9.0/tests/test_t1_2_chunks.py +263 -0
  169. gossamer_web-0.9.0/tests/test_t1_2_pages.py +322 -0
  170. gossamer_web-0.9.0/tests/test_t1_3_provenance.py +373 -0
  171. gossamer_web-0.9.0/tests/test_t1_4_conditional.py +319 -0
  172. gossamer_web-0.9.0/tests/test_t1_sections.py +285 -0
  173. gossamer_web-0.9.0/tests/test_t2_6_observability.py +275 -0
  174. gossamer_web-0.9.0/tests/test_t2_7_transport.py +151 -0
  175. gossamer_web-0.9.0/tests/test_t2_8_search_cache.py +238 -0
  176. gossamer_web-0.9.0/tests/test_t2_9_async.py +102 -0
  177. gossamer_web-0.9.0/tests/test_t3_10_formats.py +312 -0
  178. gossamer_web-0.9.0/tests/test_t3_11_tables.py +334 -0
  179. gossamer_web-0.9.0/tests/test_t3_12_discovery.py +355 -0
  180. gossamer_web-0.9.0/tests/test_t3_13_research.py +324 -0
  181. gossamer_web-0.9.0/tests/test_wave3_adapters.py +268 -0
  182. gossamer_web-0.9.0/uv.lock +1613 -0
@@ -0,0 +1,37 @@
1
+ # CodeRadar project configuration
2
+ # Generated by `coderadar init` on 2026-08-24T23:23:19.765004
3
+ #
4
+ # `coderadar analyze` prints a line naming any key it could not use, so a
5
+ # stale or misspelled setting here will say so rather than sit silent.
6
+
7
+ [project]
8
+ # Narrow the walk to these subdirectories; omitted, the whole root is walked.
9
+ # roots = ["src/", "tests/"]
10
+ exclude = ["**/__pycache__/**", "**/.venv/**", "**/node_modules/**", "**/target/**", ".gossamer_cache/**"]
11
+
12
+ [database]
13
+ path = ".coderadar/store/coderadar.db"
14
+
15
+ [embedding]
16
+ # Index-time and query-time must name the same model: a dimension mismatch
17
+ # produces confident nonsense rather than an error.
18
+ model = "BAAI/bge-small-en-v1.5"
19
+ dimension = 384
20
+ batch_size = 32
21
+
22
+ [watch]
23
+ debounce_ms = 100
24
+ max_file_size_bytes = 1048576
25
+
26
+ [mutation]
27
+ enabled = true
28
+ default_dry_run = true
29
+ allow = ["src/", "lib/", "tests/", "scripts/", "gossamer/"]
30
+ deny = [".git/", ".coderadar/", "/migrations/", "/*.lock", "/generated/"]
31
+
32
+ [resolution]
33
+ min_confidence = 0.3
34
+
35
+ [resolution.import_graph]
36
+ max_import_depth = 3
37
+ include_same_package = true
@@ -0,0 +1,120 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master, dev]
6
+ pull_request:
7
+ branches: [main, master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, windows-latest]
16
+ python-version: ['3.10', '3.11', '3.12', '3.13']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+
26
+ - name: Install Rust
27
+ uses: dtolnay/rust-toolchain@stable
28
+
29
+ - name: Cache Rust dependencies
30
+ uses: actions/cache@v4
31
+ with:
32
+ path: |
33
+ ~/.cargo/registry
34
+ ~/.cargo/git
35
+ target
36
+ key: ${{ runner.os }}-rust-${{ hashFiles('**/Cargo.lock') }}
37
+ restore-keys: |
38
+ ${{ runner.os }}-rust-
39
+
40
+ - name: Create virtual environment
41
+ run: python -m venv .venv
42
+
43
+ # The maturin build backend is pulled in by pip's build isolation,
44
+ # so no separate maturin install or `maturin develop` step is needed.
45
+ # Installing the package via its metadata is what validates the
46
+ # runtime dependency declarations (P1).
47
+ - name: Install package with dependencies (Linux/macOS)
48
+ if: runner.os != 'Windows'
49
+ run: |
50
+ ./.venv/bin/pip install -e ".[mcp,documents]"
51
+ ./.venv/bin/pip install -r requirements.txt
52
+
53
+ - name: Install package with dependencies (Windows)
54
+ if: runner.os == 'Windows'
55
+ run: |
56
+ .venv\Scripts\pip.exe install -e ".[mcp,documents]"
57
+ .venv\Scripts\pip.exe install -r requirements.txt
58
+
59
+ - name: Run tests (Linux/macOS)
60
+ if: runner.os != 'Windows'
61
+ run: ./.venv/bin/pytest tests/ -v --tb=short
62
+
63
+ - name: Run tests (Windows)
64
+ if: runner.os == 'Windows'
65
+ run: .venv\Scripts\pytest.exe tests/ -v --tb=short
66
+
67
+ supply-chain:
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+
72
+ - name: Set up Python
73
+ uses: actions/setup-python@v5
74
+ with:
75
+ python-version: '3.12'
76
+
77
+ # Audit the installed runtime + extra dependencies against the OSV
78
+ # vulnerability database. Given PyPI-targeting worm campaigns of the
79
+ # past year, this is a hard gate, not a warning.
80
+ - name: pip-audit
81
+ run: |
82
+ python -m venv /tmp/auditenv
83
+ # The runner-bundled pip is often itself advisory-flagged —
84
+ # upgrade it inside the venv so the audit covers our dependencies,
85
+ # not the runner image.
86
+ /tmp/auditenv/bin/pip install --quiet --upgrade pip
87
+ /tmp/auditenv/bin/pip install --quiet pip-audit
88
+ /tmp/auditenv/bin/pip install --quiet -e ".[mcp,documents]"
89
+ /tmp/auditenv/bin/pip-audit
90
+
91
+ # Audit the Rust dependency tree (Cargo.lock) against OSV — the same
92
+ # database pip-audit uses, which mirrors RustSec. Stdlib-only script,
93
+ # no cargo toolchain step (cargo-audit's crates.io release is stale and
94
+ # its prebuilt binaries are a moving target).
95
+ - name: cargo audit (OSV)
96
+ run: python scripts/audit_cargo.py
97
+
98
+ lint:
99
+ runs-on: ubuntu-latest
100
+ steps:
101
+ - uses: actions/checkout@v4
102
+
103
+ - name: Set up Python
104
+ uses: actions/setup-python@v5
105
+ with:
106
+ python-version: '3.12'
107
+
108
+ - name: Install Rust
109
+ uses: dtolnay/rust-toolchain@stable
110
+ with:
111
+ components: clippy
112
+
113
+ - name: Rust clippy
114
+ run: cargo clippy --all-targets -- -D warnings
115
+
116
+ - name: Install Python linting tools
117
+ run: pip install "ruff==0.16.4"
118
+
119
+ - name: Run ruff
120
+ run: ruff check gossamer/
@@ -0,0 +1,160 @@
1
+ name: Release
2
+
3
+ # Publishing happens on version tag push (e.g. `git tag v0.9.0 && git push
4
+ # origin v0.9.0`). The tag MUST match Cargo.toml/pyproject.toml — enforced
5
+ # by the check-tag job below.
6
+
7
+ on:
8
+ push:
9
+ tags:
10
+ - 'v*.*.*'
11
+
12
+ jobs:
13
+ check-tag:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Tag matches package version
19
+ run: |
20
+ TAG="${GITHUB_REF#refs/tags/v}"
21
+ CARGO=$(grep '^version' Cargo.toml | head -1 | cut -d'"' -f2)
22
+ PYPROJ=$(grep '^version' pyproject.toml | head -1 | cut -d'"' -f2)
23
+ echo "tag=$TAG cargo=$CARGO pyproject=$PYPROJ"
24
+ [ "$TAG" = "$CARGO" ] && [ "$TAG" = "$PYPROJ" ] || {
25
+ echo "::error::tag v$TAG != Cargo.toml ($CARGO) / pyproject.toml ($PYPROJ)"
26
+ exit 1
27
+ }
28
+
29
+ build-wheels:
30
+ needs: check-tag
31
+ runs-on: ${{ matrix.os }}
32
+ strategy:
33
+ fail-fast: false
34
+ matrix:
35
+ os: [ubuntu-latest, windows-latest, macos-latest]
36
+ # Single interpreter per OS: pyo3 abi3-py38 makes one wheel per
37
+ # platform installable on every supported Python (>=3.10).
38
+ python-version: ['3.12']
39
+
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+
43
+ - name: Set up Python
44
+ uses: actions/setup-python@v5
45
+ with:
46
+ python-version: ${{ matrix.python-version }}
47
+
48
+ # manylinux: auditwheel-repaired portable Linux wheels — plain
49
+ # `maturin build` emits linux_x86_64 wheels that PyPI REJECTS.
50
+ # (macOS/Windows need no equivalent; the flag is Linux-only.)
51
+ - name: Build wheel (Linux, manylinux)
52
+ if: runner.os == 'Linux'
53
+ uses: PyO3/maturin-action@v1
54
+ with:
55
+ command: build
56
+ args: --release --out dist
57
+ manylinux: auto
58
+
59
+ - name: Build wheel (macOS / Windows)
60
+ if: runner.os != 'Linux'
61
+ uses: PyO3/maturin-action@v1
62
+ with:
63
+ command: build
64
+ args: --release --out dist
65
+
66
+ - name: Upload wheel artifact
67
+ uses: actions/upload-artifact@v4
68
+ with:
69
+ name: wheels-${{ runner.os }}
70
+ path: dist/*.whl
71
+
72
+ build-sdist:
73
+ needs: check-tag
74
+ runs-on: ubuntu-latest
75
+ steps:
76
+ - uses: actions/checkout@v4
77
+
78
+ - name: Set up Python
79
+ uses: actions/setup-python@v5
80
+ with:
81
+ python-version: '3.12'
82
+
83
+ - name: Install Rust
84
+ uses: dtolnay/rust-toolchain@stable
85
+
86
+ - name: Install maturin
87
+ run: pip install "maturin>=1.0,<2.0"
88
+
89
+ # Needs network: resolves the meta_oxide git dependency. sdist
90
+ # consumers rebuild from source, so this is expected.
91
+ - name: Build sdist
92
+ run: maturin sdist --out dist
93
+
94
+ - name: Upload sdist artifact
95
+ uses: actions/upload-artifact@v4
96
+ with:
97
+ name: sdist
98
+ path: dist/*.tar.gz
99
+
100
+ publish:
101
+ needs: [build-wheels, build-sdist]
102
+ runs-on: ubuntu-latest
103
+ if: startsWith(github.ref, 'refs/tags/')
104
+ permissions:
105
+ contents: write # GitHub Release
106
+ id-token: write # PyPI Trusted Publishing (OIDC, no secret)
107
+
108
+ steps:
109
+ - name: Download artifacts
110
+ uses: actions/download-artifact@v4
111
+ with:
112
+ pattern: wheels-*
113
+ path: dist
114
+ merge-multiple: true
115
+
116
+ - name: Download sdist
117
+ uses: actions/download-artifact@v4
118
+ with:
119
+ name: sdist
120
+ path: dist
121
+
122
+ # A GitHub Release with the wheels is created for every tag, with or
123
+ # without PyPI credentials, so released versions are always
124
+ # downloadable and pinnable from GitHub.
125
+ - name: Create GitHub Release
126
+ uses: softprops/action-gh-release@v2
127
+ with:
128
+ files: dist/*
129
+ generate_release_notes: true
130
+
131
+ - name: Check PyPI token
132
+ id: token
133
+ env:
134
+ TOKEN: ${{ secrets.PYPI_API_TOKEN }}
135
+ run: |
136
+ if [ -n "$TOKEN" ]; then echo "has=true" >> "$GITHUB_OUTPUT"; fi
137
+
138
+ # Preferred: Trusted Publishing (configure once on PyPI: project
139
+ # settings → trusted publisher = this repo + release.yml workflow).
140
+ # Falls back to PYPI_API_TOKEN when OIDC is unavailable.
141
+ - name: Publish to PyPI (trusted publishing)
142
+ id: oidc
143
+ continue-on-error: true
144
+ uses: pypa/gh-action-pypi-publish@release/v1
145
+
146
+ - name: Publish to PyPI (API token)
147
+ if: steps.oidc.outcome == 'failure' && steps.token.outputs.has == 'true'
148
+ uses: pypa/gh-action-pypi-publish@release/v1
149
+ with:
150
+ password: ${{ secrets.PYPI_API_TOKEN }}
151
+
152
+ - name: Publish outcome
153
+ run: |
154
+ if [ "${{ steps.oidc.outcome }}" = "success" ]; then
155
+ echo "PyPI publish: trusted publishing OK"
156
+ elif [ "${{ steps.token.outputs.has }}" = "true" ]; then
157
+ echo "PyPI publish: API token path taken (check step above)"
158
+ else
159
+ echo "::notice::PyPI publish skipped — no trusted publisher and no PYPI_API_TOKEN secret. Wheels are on the GitHub Release."
160
+ fi
@@ -0,0 +1,54 @@
1
+ # CodeRadar index
2
+ .coderadar/
3
+
4
+ # Rust build artifacts
5
+ /target/
6
+ **/*.rs.bk
7
+
8
+ # Python bytecode & caches
9
+ __pycache__/
10
+ *.py[cod]
11
+ *$py.class
12
+ .pytest_cache/
13
+ .mypy_cache/
14
+ .ruff_cache/
15
+
16
+ # Compiled extension (built via maturin; rebuild with `maturin develop`)
17
+ *.so
18
+ *.pyd
19
+ # Windows debug symbols from the built extension (churns on every rebuild).
20
+ *.pdb
21
+
22
+ # Packaging
23
+ build/
24
+ dist/
25
+ *.egg-info/
26
+
27
+ # Virtual environments
28
+ .venv/
29
+ venv/
30
+ env/
31
+
32
+ # Runtime caches
33
+ .gossamer_cache/
34
+ .web_research_cache/
35
+ stored_documents/
36
+
37
+ # Editors / OS
38
+ .vscode/
39
+ .idea/
40
+ .DS_Store
41
+ Thumbs.db
42
+ crash.log
43
+
44
+ # Scratch artifacts
45
+ step1_links.json
46
+ wiki_topics.json
47
+
48
+ # Windows device-name artifact (prevents accidental indexing)
49
+ nul
50
+
51
+ # Local planning spillover (audits, provider research, internal plans).
52
+ # Deliberately unsynced: working notes live here, the repo keeps only
53
+ # docs/QUICKREF.md + docs/ARCHITECTURE.md as its synced record.
54
+ /planning/
@@ -0,0 +1,23 @@
1
+ # AGENTS.md — gossamer
2
+
3
+ Web research toolkit (Python + Rust). For any task needing **current external
4
+ information** (docs, APIs, papers, case law, market data, patents), use
5
+ gossamer instead of guessing or raw curl loops.
6
+
7
+ - **MCP** (if configured): 10 tools — `web_search`, `inspect_html_page`,
8
+ `batch_inspect_pages`, `extract_document`, `discover_resources`,
9
+ `crawl`, `manage_cache`, `research_by_category`,
10
+ `export_citations`, `check_sources`.
11
+ - **CLI** (always available, mirrors all 10 MCP tools 1:1):
12
+ `gossamer search|research|categories|inspect|batch|extract|check|discover|crawl|cache|cite`
13
+ (or `python -m gossamer.cli …` from the project venv).
14
+ - **Routing**: `gossamer categories` prints the live category → provider
15
+ table (`scholarly`/`legal`/`patent`/`financial`/`geo`). Patent providers
16
+ are key-gated — surface missing-key errors to the user, don't retry.
17
+ - **Budgets**: keep crawls ≤ 15 pages, set `max_tokens`, extract page ranges.
18
+ - **Keys**: `~/.gossamer/keys.json` (`python -m gossamer.keystore --init`);
19
+ never put secrets in configs or prompts.
20
+
21
+ Dev: `.venv/Scripts/python.exe -m pytest -q` (full suite),
22
+ `ruff check gossamer/`, `maturin develop --release` after touching `src/`.
23
+ Target branch for changes: `dev`.