Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
3d1c570
fixed tailscale-serve commit
thestumonkey Jan 28, 2026
ab48fd6
Merge pull request #141 from Ushadow-io/mainfix
thestumonkey Jan 28, 2026
eb201f5
Omi app logs (#142)
thestumonkey Jan 29, 2026
5588246
Omi app logs (#143)
thestumonkey Jan 29, 2026
c259226
Add debug logging for service deployment
thestumonkey Jan 29, 2026
ca2b0af
simplified to just use ushadow network
thestumonkey Jan 29, 2026
6fceb9a
added nbetwork fixes and chronicle combined audio
thestumonkey Jan 29, 2026
b709610
fixed chronicle port issue
thestumonkey Jan 30, 2026
4cdd66a
updated openmem
thestumonkey Jan 30, 2026
a9729e5
added pull logic if image not found
thestumonkey Jan 30, 2026
d6e34e8
added locked neo4j driver version
thestumonkey Jan 30, 2026
0616abf
added mobile session logger
thestumonkey Jan 30, 2026
7821266
added pixi
thestumonkey Jan 30, 2026
dc614b2
Convert chronicle to git submodule
thestumonkey Feb 1, 2026
75211c0
Remove orphaned vibe-kanban submodule entry
thestumonkey Feb 1, 2026
70a9ede
Add automatic sparse checkout configuration via git hooks
thestumonkey Feb 1, 2026
33b4236
Add Makefile targets for building/pushing Chronicle and Mycelia to GHCR
thestumonkey Feb 1, 2026
3f0b8f3
Add OpenMemory (mem0) as submodule with build support
thestumonkey Feb 1, 2026
5e75d85
chat and memories
thestumonkey Feb 1, 2026
9ba036d
new convo page
thestumonkey Feb 2, 2026
cf81775
9548 simpler deploys (#145)
thestumonkey Feb 2, 2026
44390e1
feat: Add Keycloak OAuth theme matching Ushadow design system
thestumonkey Feb 2, 2026
97c913e
security: Move Keycloak credentials to environment variables
thestumonkey Feb 2, 2026
198f02a
Kaycloak
thestumonkey Feb 2, 2026
9936bd9
memorycards and dualstream recording
thestumonkey Feb 2, 2026
b192c01
Merge PR #147: Add Keycloak OAuth theme and security improvements
thestumonkey Feb 2, 2026
28d262a
feat: Add Keycloak OAuth implementation
thestumonkey Feb 2, 2026
dd21556
F13f auth complete (#149)
thestumonkey Feb 2, 2026
cfb6d50
Revert "F13f auth complete (#149)" (#150)
thestumonkey Feb 2, 2026
00cffb9
F13f auth complete (#151)
thestumonkey Feb 2, 2026
cb13bd5
feat: Add automatic Keycloak redirect URI registration
thestumonkey Feb 2, 2026
fdd7521
Merge origin/dev into f13f-auth-complete
thestumonkey Feb 2, 2026
54b3ee6
feat: Add Keycloak SSO integration with conversation sharing (#152)
thestumonkey Feb 3, 2026
588a3cf
Add ingress configuration UI to DeployToK8sModal
thestumonkey Feb 3, 2026
5e68c01
feat: Add kubernetes cluster ingress configuration
thestumonkey Feb 3, 2026
fd09c19
Merge remote-tracking branch 'origin/dev' into dual-convo
thestumonkey Feb 3, 2026
224a441
fix: Resolve merge conflict in App.tsx - keep KeycloakAuthProvider
thestumonkey Feb 3, 2026
bb78374
fix: Resolve merge conflicts in ConversationDetailPage - add share fu…
thestumonkey Feb 3, 2026
b0ed4cc
feat: Add Keycloak user compatibility across all routers
thestumonkey Feb 3, 2026
1ccf8e3
fix: Resolve merge conflicts in keycloak_user_sync - use display_name
thestumonkey Feb 3, 2026
b6faaf3
fix: Handle Keycloak user dict in /users/me endpoint
thestumonkey Feb 3, 2026
b777879
feat: Add token bridging to audio relay WebSocket
thestumonkey Feb 3, 2026
407b9fc
fix: Add codec parameter to audio relay destinations
thestumonkey Feb 3, 2026
f04d9ad
fixed audiorelay codec
thestumonkey Feb 3, 2026
af6f7c0
upgraded mobile
thestumonkey Feb 3, 2026
41b0f00
refactor: Update setup scripts and documentation
skywinder Feb 3, 2026
bc9d487
Add Chronicle-powered dashboard with recent activities
thestumonkey Feb 2, 2026
59d0c69
added postgres as default
thestumonkey Feb 3, 2026
e555d09
added kc realm
thestumonkey Feb 3, 2026
505b651
made mycelia default service
thestumonkey Feb 3, 2026
2612045
aded method indeox for claude
thestumonkey Feb 3, 2026
fae2753
docs: Update README with infrastructure startup instructions
skywinder Feb 3, 2026
47522f4
feat: Add env sync tool to sync .env with .env.example (#154)
skywinder Feb 3, 2026
3aae272
Merge branch 'dev' into sky-dev
skywinder Feb 4, 2026
afbfcd9
fix: use directory mount for keycloak realm import
skywinder Feb 4, 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
55 changes: 55 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Ushadow Environment Configuration Template
# Copy this file to .env and customize for your environment
# DO NOT COMMIT .env - it contains environment-specific configuration

# ==========================================
# ENVIRONMENT & PROJECT NAMING
# ==========================================
ENV_NAME=ushadow
COMPOSE_PROJECT_NAME=ushadow

# ==========================================
# PORT CONFIGURATION
# ==========================================
PORT_OFFSET=10
BACKEND_PORT=8010
WEBUI_PORT=3010

# ==========================================
# DATABASE ISOLATION
# ==========================================
MONGODB_DATABASE=ushadow
REDIS_DATABASE=0

# ==========================================
# CORS & FRONTEND CONFIGURATION
# ==========================================
CORS_ORIGINS=http://localhost:3010,http://127.0.0.1:3010,http://localhost:8010,http://127.0.0.1:8010
VITE_BACKEND_URL=http://localhost:8010
VITE_ENV_NAME=ushadow
HOST_IP=localhost

# Development mode
DEV_MODE=true

# ==========================================
# SHARE LINK CONFIGURATION
# ==========================================
# Base URL for share links (highest priority if set)
# SHARE_BASE_URL=https://ushadow.tail12345.ts.net

# Public gateway URL for external friend sharing (requires share-gateway deployment)
# SHARE_PUBLIC_GATEWAY=https://share.yourdomain.com

# Share feature toggles
SHARE_VALIDATE_RESOURCES=false # Enable strict resource validation
SHARE_VALIDATE_TAILSCALE=false # Enable Tailscale IP validation

# ==========================================
# KEYCLOAK CONFIGURATION
# ==========================================
# SECURITY: Change these defaults in production!
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=changeme
KEYCLOAK_PORT=8081
KEYCLOAK_MGMT_PORT=9000
49 changes: 49 additions & 0 deletions .githooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Git Hooks

This directory contains git hooks that are **committed to the repository**.

## Setup (One-Time)

After cloning, configure git to use these hooks:

```bash
git config core.hooksPath .githooks
```

## Automatic Setup

Add this to your `~/.gitconfig` to automatically use `.githooks` in all repos:

```ini
[init]
templateDir = ~/.git-templates
```

Then create `~/.git-templates/hooks/post-clone`:
```bash
#!/bin/bash
if [ -d .githooks ]; then
git config core.hooksPath .githooks
fi
```

## Available Hooks

### post-checkout
Automatically configures sparse checkout for chronicle and mycelia submodules to prevent circular dependencies.

**What it does:**
- Chronicle: Excludes `extras/mycelia/`
- Mycelia: Excludes `friend/`

**When it runs:**
- After `git checkout`
- After `git submodule update`
- After initial clone (with setup)

## Testing

Test the hook manually:
```bash
./.githooks/post-checkout
```
45 changes: 45 additions & 0 deletions .githooks/post-checkout
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/bash
# Post-checkout hook to configure sparse checkout for submodules
# This prevents circular dependencies between chronicle and mycelia

set -e

echo "🔧 Configuring sparse checkout for submodules..."

# Configure chronicle to exclude extras/mycelia
if [ -d "chronicle" ]; then
CHRONICLE_GIT="$(cd chronicle && git rev-parse --git-dir 2>/dev/null || echo "")"
if [ -n "$CHRONICLE_GIT" ] && [ -d "$CHRONICLE_GIT" ]; then
echo " 📁 Configuring chronicle (excluding extras/mycelia)"
mkdir -p "$CHRONICLE_GIT/info"
cat > "$CHRONICLE_GIT/info/sparse-checkout" <<'SPARSE'
/*
!extras/mycelia/
SPARSE
(cd chronicle && git config core.sparseCheckout true && git read-tree -mu HEAD 2>/dev/null || true)
fi
fi

# Configure mycelia to exclude friend
if [ -d "mycelia" ]; then
MYCELIA_GIT="$(cd mycelia && git rev-parse --git-dir 2>/dev/null || echo "")"
if [ -n "$MYCELIA_GIT" ] && [ -d "$MYCELIA_GIT" ]; then
echo " 📁 Configuring mycelia (excluding friend)"
mkdir -p "$MYCELIA_GIT/info"
cat > "$MYCELIA_GIT/info/sparse-checkout" <<'SPARSE'
/*
!friend/
SPARSE
(cd mycelia && git config core.sparseCheckout true && git read-tree -mu HEAD 2>/dev/null || true)
fi
fi

# Configure openmemory (no exclusions needed currently)
if [ -d "openmemory" ]; then
OPENMEMORY_GIT="$(cd openmemory && git rev-parse --git-dir 2>/dev/null || echo "")"
if [ -n "$OPENMEMORY_GIT" ] && [ -d "$OPENMEMORY_GIT" ]; then
echo " 📁 Openmemory configured (no exclusions)"
fi
fi

echo "✅ Sparse checkout configured successfully"
12 changes: 12 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[submodule "chronicle"]
path = chronicle
url = https://github.com/Ushadow-io/chronicle.git
update = checkout

[submodule "mycelia"]
path = mycelia
url = https://github.com/mycelia-tech/mycelia.git
update = checkout
[submodule "openmemory"]
path = openmemory
url = https://github.com/Ushadow-io/mem0.git
193 changes: 193 additions & 0 deletions DECISION_POINT_1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# Decision Point #1: Resource Validation

## Current Status

✅ **Feature is ready to use** - Sharing works with lazy validation (no resource checking)
📝 **Your choice** - Implement strict validation if you want to prevent broken share links

## How It Works Now

When you create a share link, the system:
1. ✅ Creates share token in MongoDB
2. ✅ Generates share URL
3. ⚠️ **Does NOT verify** the conversation/resource exists
4. ✅ Returns link to user

**Result**: Share links are created instantly, but might be broken if the resource doesn't exist.

---

## Enabling Strict Validation

### Step 1: Set Environment Variable

Add to your `.env` file:
```bash
SHARE_VALIDATE_RESOURCES=true
```

This tells the share service to validate resources before creating share links.

### Step 2: Implement Validation Logic

**Location**: `ushadow/backend/src/services/share_service.py` line ~340

I've prepared the function structure. You need to add **5-10 lines** of code to validate the resource exists.

---

## Implementation Options

Since Mycelia uses a resource-based API (not REST), you have two approaches:

### Option A: Validate via Mycelia Objects API (Recommended)

```python
# In _validate_resource_exists(), around line 340:

if resource_type == ResourceType.CONVERSATION:
try:
async with httpx.AsyncClient(timeout=5.0) as client:
# Call Mycelia objects resource with "get" action
response = await client.post(
"http://mycelia-backend:8000/api/resource/tech.mycelia.objects",
json={
"action": "get",
"id": resource_id
},
headers={"Authorization": f"Bearer {self._get_service_token()}"}
)

if response.status_code == 404:
raise ValueError(f"Conversation {resource_id} not found in Mycelia")
elif response.status_code != 200:
raise ValueError(f"Failed to validate conversation: {response.status_code}")

except httpx.RequestError as e:
logger.error(f"Failed to connect to Mycelia: {e}")
raise ValueError("Could not connect to Mycelia to validate conversation")
```

**Pros**: Validates against Mycelia directly
**Cons**: Requires service token for authentication

---

### Option B: Validate via Ushadow Generic Proxy

```python
if resource_type == ResourceType.CONVERSATION:
try:
async with httpx.AsyncClient(timeout=5.0) as client:
# Use ushadow's generic proxy to Mycelia
response = await client.post(
"http://localhost:8080/api/services/mycelia-backend/proxy/api/resource/tech.mycelia.objects",
json={
"action": "get",
"id": resource_id
}
)

if response.status_code == 404:
raise ValueError(f"Conversation {resource_id} not found")
elif response.status_code != 200:
raise ValueError(f"Failed to validate conversation: {response.status_code}")

except httpx.RequestError as e:
logger.error(f"Mycelia validation failed: {e}")
raise ValueError("Could not validate conversation")
```

**Pros**: Leverages existing proxy, handles auth automatically
**Cons**: Assumes ushadow proxy is available

---

### Option C: Skip Validation (Current Behavior)

Don't set `SHARE_VALIDATE_RESOURCES=true` and leave the TODO as-is.

**Pros**: Instant share creation, no API calls
**Cons**: Users might create broken share links

---

## Trade-offs to Consider

| Aspect | Lazy Validation | Strict Validation |
|--------|----------------|-------------------|
| **Speed** | ✅ Instant (~5ms) | ⚠️ Slower (~50-100ms) |
| **Reliability** | ⚠️ Might create broken links | ✅ Only valid links |
| **UX** | ✅ Fast feedback | ⚠️ Slight delay |
| **Dependencies** | ✅ No backend calls | ⚠️ Requires Mycelia/Chronicle |
| **Error handling** | ⚠️ Broken links fail silently | ✅ Immediate error feedback |

---

## My Recommendation

**Start with Lazy Validation (current behavior)** because:
1. It's simpler - no extra code needed
2. Users rarely share non-existent conversations
3. When they access a broken link, they get a clear "not found" error
4. You can always add strict validation later if needed

**Implement Strict Validation if:**
- You have frequent issues with broken share links
- You want immediate feedback during share creation
- The ~50-100ms delay is acceptable for your UX

---

## Testing Your Implementation

Once you've implemented validation:

```bash
# Test with valid conversation
curl -X POST http://localhost:8080/api/share/create \
-H "Content-Type: application/json" \
-H "Cookie: ushadow_auth=YOUR_TOKEN" \
-d '{
"resource_type": "conversation",
"resource_id": "VALID_CONVERSATION_ID",
"permissions": ["read"]
}'

# Expected: 201 Created with share URL

# Test with invalid conversation
curl -X POST http://localhost:8080/api/share/create \
-H "Content-Type: application/json" \
-H "Cookie: ushadow_auth=YOUR_TOKEN" \
-d '{
"resource_type": "conversation",
"resource_id": "INVALID_ID_12345",
"permissions": ["read"]
}'

# Expected: 400 Bad Request with "Conversation not found" error
```

---

## Questions?

**Q: What if Mycelia/Chronicle is down during validation?**
A: The validation will fail with "Could not connect" error, preventing share creation. Consider adding retry logic or circuit breaker.

**Q: Should I validate memories too?**
A: Yes, add similar logic for `ResourceType.MEMORY` if users can share individual memories.

**Q: Can I validate asynchronously (background job)?**
A: Not recommended - user needs immediate feedback. If validation is slow, consider caching resource existence.

---

## Next Steps

1. **Decide**: Lazy vs Strict validation
2. **If Strict**: Set `SHARE_VALIDATE_RESOURCES=true` in `.env`
3. **Implement**: Add 5-10 lines in `share_service.py` (see options above)
4. **Test**: Create shares with valid/invalid IDs
5. **Move to Decision Point #2**: User authorization checks
Loading
Loading