Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
82ebd2a
Add OG meta tags to demo and dashboard pages
neuromechanist Feb 13, 2026
e7fe289
Add OSA logo, dark mode, and branded footer
neuromechanist Feb 13, 2026
b686736
Reorder footer: copyright holder first, then made with love
neuromechanist Feb 13, 2026
d86d7e9
Fix review issues: dark mode, meta tags, broken links
neuromechanist Feb 13, 2026
2381d79
Enforce mandatory HED tag validation before display (#211)
neuromechanist Feb 18, 2026
f77d8fd
Fix sync status page: community-aware, all sync types, N/A display (#…
neuromechanist Feb 18, 2026
b9cf46c
Bump version to 0.6.7.dev0
neuromechanist Feb 18, 2026
839c49b
Address PR review findings
neuromechanist Feb 18, 2026
533b9c3
Fix logging: add exc_info and upgrade scheduler warning to error
neuromechanist Feb 18, 2026
b87cf66
Merge main into develop, resolve version conflict
neuromechanist Feb 18, 2026
22ae3fb
Refactor CLI to thin client architecture (#216)
neuromechanist Feb 19, 2026
ee685ae
Fix BYOK header name inconsistency
neuromechanist Feb 19, 2026
bd95968
Update in-repo docs for thin client CLI
neuromechanist Feb 19, 2026
b14c806
Address PR review: simplify code, fix error handling
neuromechanist Feb 19, 2026
5dd8751
ci: add workflow to notify documentation repo on push to main
neuromechanist Feb 19, 2026
c32f5e7
Surface community config health via public API (#221)
neuromechanist Feb 24, 2026
326d656
Show config health warnings on status dashboard (#222)
neuromechanist Feb 24, 2026
cbd4609
Add warning for communities using platform key (#223)
neuromechanist Feb 25, 2026
b19cf8d
Add community-specific logos to chat widget (#226)
neuromechanist Feb 25, 2026
cff0de4
Add FieldTrip community, generalize docstring/FAQ tools (#227)
neuromechanist Feb 25, 2026
a0115f7
chore: sync worker CORS from community configs [skip ci]
github-actions[bot] Feb 25, 2026
c8548ff
Address release review: error handling, logging, tests (#228)
neuromechanist Feb 25, 2026
ed29ccd
Merge remote-tracking branch 'origin/main' into merge-develop-to-main
neuromechanist Feb 25, 2026
c229fd1
fix: add theme_color to WidgetConfigResponse
neuromechanist Feb 25, 2026
ee6b793
feat: onboard MNE-Python community with Discourse syncer (#230)
neuromechanist Feb 25, 2026
ebef53e
chore: sync worker CORS from community configs [skip ci]
github-actions[bot] Feb 25, 2026
5d68353
Remove CORS origins for MNE and FieldTrip (#231)
neuromechanist Feb 25, 2026
20064e9
chore: sync worker CORS from community configs [skip ci]
github-actions[bot] Feb 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .context/local-testing-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,17 @@ curl -X POST http://localhost:38528/COMMUNITY_ID/ask \
-d '{"question": "What is this tool?", "api_key": "your-key"}' | jq
```

## CLI Testing (No Server Needed)
## CLI Testing

```bash
# Interactive chat
uv run osa chat --community COMMUNITY_ID --standalone
# Interactive chat (connects to API by default)
uv run osa chat -a COMMUNITY_ID

# Single question
uv run osa ask --community COMMUNITY_ID "What is this tool?" --standalone
uv run osa ask -a COMMUNITY_ID "What is this tool?"

# Against local server
uv run osa ask -a COMMUNITY_ID "What is this tool?" --api-url http://localhost:38528
```

## Knowledge Sync
Expand All @@ -69,7 +72,7 @@ uv run osa sync papers --community COMMUNITY_ID --citations
- [ ] Preloaded docs are in context
- [ ] On-demand docs retrieved when relevant
- [ ] Documentation URLs in responses are valid
- [ ] CLI standalone mode works
- [ ] CLI works against local server
- [ ] Knowledge sync completes (if configured)
- [ ] Assistant does not hallucinate PR/issue numbers

Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/notify-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Notify Documentation Repo

on:
push:
branches:
- main

jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Dispatch to documentation repo
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.DOCS_REPO_TOKEN }}
repository: OpenScience-Collective/documentation
event-type: osa-updated
client-payload: '{"sha": "${{ github.sha }}", "ref": "${{ github.ref }}"}'
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,23 @@ uv run pre-commit install
### CLI Usage

```bash
# Show available assistants
osa
# Set up your API key (get one at https://openrouter.ai/keys)
osa init

# Ask the HED assistant a question
osa hed ask "What is HED?"
osa ask -a hed "What is HED?"

# Start an interactive chat session
osa hed chat
osa chat -a hed

# Show all commands
osa --help
osa hed --help
```

### API Server

Requires server dependencies: `pip install 'open-science-assistant[server]'`

```bash
# Start the API server
osa serve
Expand All @@ -77,8 +78,8 @@ osa config show
# Set API keys for BYOK (Bring Your Own Key)
osa config set --openrouter-key YOUR_KEY

# Connect to remote server (uses BYOK)
osa hed ask "What is HED?" --url https://api.osc.earth/osa-dev
# Override API URL per-command
osa ask -a hed "What is HED?" --api-url https://api.osc.earth/osa-dev
```

### Deployment
Expand Down
38 changes: 38 additions & 0 deletions dashboard/osa/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,31 @@
.status-error { background: #fee2e2; color: #991b1b; }
.status-unknown { background: #f1f5f9; color: #64748b; }

/* Config health banners */
.config-banner {
border-radius: 8px;
padding: 0.7rem 1rem;
margin-bottom: 1rem;
font-size: 0.85rem;
line-height: 1.5;
}
.config-banner ul {
list-style: none;
margin: 0;
padding: 0;
}
.config-banner li { padding: 0.1rem 0; }
.config-banner-warning {
background: #fff7ed;
border: 1px solid #fed7aa;
color: #9a3412;
}
.config-banner-error {
background: #fef2f2;
border: 1px solid #fecaca;
color: #991b1b;
}

/* Period toggle */
.period-toggle { display: flex; gap: 0.35rem; margin-bottom: 1rem; }
.period-btn {
Expand Down Expand Up @@ -801,6 +826,18 @@ <h2>Communities</h2>
healthLabel = healthStatus.charAt(0).toUpperCase() + healthStatus.slice(1);
}

// Config health from public metrics (API key, docs status)
const configHealth = summary.config_health || null;
let configWarningHtml = '';
if (configHealth && configHealth.warnings && configHealth.warnings.length > 0) {
const warningItems = configHealth.warnings.map(w => `<li>${escapeHtml(w)}</li>`).join('');
const bannerClass = configHealth.status === 'error' ? 'config-banner-error' : 'config-banner-warning';
configWarningHtml = `
<div class="config-banner ${bannerClass}">
<ul>${warningItems}</ul>
</div>`;
}

const desc = meta.description
? `<p style="color:#64748b; font-size:0.9rem; margin-bottom:0.75rem;">${escapeHtml(meta.description)}</p>`
: '';
Expand All @@ -815,6 +852,7 @@ <h2>${safeName.toUpperCase()}</h2>
</div>
${desc}
${links}
${configWarningHtml}
<div class="overview-grid">
<div class="metric">
<div class="metric-value">${summary.total_requests.toLocaleString()}</div>
Expand Down
49 changes: 23 additions & 26 deletions deploy/DEPLOYMENT_ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Users can pass their own API keys via HTTP headers:
|--------|----------|
| `X-OpenAI-API-Key` | OpenAI |
| `X-Anthropic-API-Key` | Anthropic |
| `X-OpenRouter-API-Key` | OpenRouter |
| `X-OpenRouter-Key` | OpenRouter |

### Authentication Policy

Expand All @@ -67,7 +67,7 @@ Users can pass their own API keys via HTTP headers:
```bash
curl -X POST https://api.osc.earth/osa-dev/hed/chat \
-H "Content-Type: application/json" \
-H "X-OpenRouter-API-Key: sk-or-your-key" \
-H "X-OpenRouter-Key: sk-or-your-key" \
-d '{"message": "What is HED?", "stream": false}'
```

Expand All @@ -76,14 +76,17 @@ No `X-API-Key` required when using BYOK headers.
### CLI Configuration for BYOK

```bash
# Set your LLM API key
# Set up your API key
osa init --api-key "sk-or-your-key"

# Or set it directly
osa config set --openrouter-key "sk-or-your-key"

# Use with remote server (BYOK)
osa hed ask "What is HED?" --url https://api.osc.earth/osa-dev
# Ask a question (uses saved key via BYOK)
osa ask -a hed "What is HED?"

# Use standalone mode (local server, no remote needed)
osa hed ask "What is HED?"
# Use against dev server
osa ask -a hed "What is HED?" --api-url https://api.osc.earth/osa-dev
```

---
Expand Down Expand Up @@ -413,10 +416,10 @@ sudo systemctl reload apache2
### Installation

```bash
# From PyPI (when published)
# From PyPI (lightweight, ~7 dependencies)
pip install open-science-assistant

# From source
# From source (with server dependencies)
git clone https://github.com/OpenScience-Collective/osa.git
cd osa
uv sync
Expand All @@ -425,37 +428,31 @@ uv sync
### Commands

```bash
# Show available assistants
osa
# Setup (saves API key securely)
osa init

# Ask a single question (standalone mode - starts local server)
osa hed ask "What is HED?"
# Ask a question
osa ask -a hed "What is HED?"

# Interactive chat session
osa hed chat
osa chat -a hed

# Use remote server with BYOK
osa hed ask "What is HED?" --url https://api.osc.earth/osa-dev
# Override API URL per-command
osa ask -a hed "What is HED?" --api-url https://api.osc.earth/osa-dev

# Configuration
osa config show # Show current config
osa config set --openrouter-key "sk-..." # Set LLM API key
osa config set --api-key "server-key" # Set server API key
osa config path # Show config file location

# Server management
osa serve # Start API server (production)
# Server management (requires pip install 'open-science-assistant[server]')
osa serve # Start API server
osa serve --port 38529 --reload # Development mode
osa health --url https://api.osc.earth/osa # Check API health
```

### Standalone vs Remote Mode

| Mode | Description | Use Case |
|------|-------------|----------|
| Standalone (default) | Starts embedded server on localhost | Local development, offline use |
| Remote (`--url`) | Connects to external API | Production, shared infrastructure |
The CLI defaults to connecting to the production API at `https://api.osc.earth/osa`. Use `--api-url` to override.

---

**Last Updated**: January 2026
**Last Updated**: February 2026
2 changes: 1 addition & 1 deletion deploy/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ COPY pyproject.toml README.md ./

# Install uv and dependencies
RUN pip install uv && \
uv pip install --system --no-cache ".[dev]"
uv pip install --system --no-cache ".[server]"

# Copy the rest of the application code
COPY src/ ./src/
Expand Down
50 changes: 50 additions & 0 deletions frontend/osa-chat-widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,13 @@
height: 20px;
}

.osa-chat-avatar img {
width: 28px;
height: 28px;
object-fit: contain;
border-radius: 50%;
}

.osa-chat-title-area {
flex: 1;
min-width: 0;
Expand Down Expand Up @@ -1502,6 +1509,19 @@
CONFIG.suggestedQuestions = w.suggested_questions;
changed = true;
}
if (w.theme_color != null && !_userSetKeys.has('themeColor')) {
CONFIG.themeColor = w.theme_color;
changed = true;
}
if (w.logo_url != null && !_userSetKeys.has('logo')) {
// Resolve path-only logo URLs (starting with '/') against the API endpoint
if (w.logo_url.startsWith('/')) {
CONFIG.logo = CONFIG.apiEndpoint + w.logo_url;
} else {
CONFIG.logo = w.logo_url;
}
changed = true;
}

if (changed) {
applyWidgetConfig();
Expand All @@ -1523,6 +1543,20 @@
const container = document.querySelector('.osa-chat-widget');
if (!container) return;

// Apply theme color if configured (must be valid #RRGGBB hex)
if (CONFIG.themeColor && /^#[0-9a-fA-F]{6}$/.test(CONFIG.themeColor)) {
container.style.setProperty('--osa-primary', CONFIG.themeColor);
// Derive a darker shade for hover states
const r = parseInt(CONFIG.themeColor.slice(1, 3), 16);
const g = parseInt(CONFIG.themeColor.slice(3, 5), 16);
const b = parseInt(CONFIG.themeColor.slice(5, 7), 16);
const darker = '#' +
Math.max(0, r - 25).toString(16).padStart(2, '0') +
Math.max(0, g - 25).toString(16).padStart(2, '0') +
Math.max(0, b - 25).toString(16).padStart(2, '0');
container.style.setProperty('--osa-primary-dark', darker);
}

// Update header title
const titleEl = container.querySelector('.osa-chat-title');
if (titleEl) {
Expand Down Expand Up @@ -1552,6 +1586,22 @@
// Update suggested questions
renderSuggestions(container);

// Update avatar with community logo if available
const avatar = container.querySelector('.osa-chat-avatar');
if (avatar && CONFIG.logo) {
const fallback = avatar.innerHTML;
const img = document.createElement('img');
img.src = CONFIG.logo;
img.alt = CONFIG.title;
img.onerror = function() {
console.warn('[OSA] Failed to load community logo:', CONFIG.logo);
avatar.innerHTML = fallback;
img.onerror = null;
};
avatar.innerHTML = '';
avatar.appendChild(img);
}

// Update loading label if currently loading
const loadingLabel = container.querySelector('.osa-loading-label');
if (loadingLabel) {
Expand Down
Loading