Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
94 changes: 61 additions & 33 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,38 +1,77 @@
# Required for OpenAI Realtime, Responses, and computer-use.
UV_NO_EDITABLE=1
# Iris configuration template.
#
# cp .env.example .env
#
# `.env` is git-ignored — never commit real keys. Only OPENAI_API_KEY is
# required; everything else has a working default or is an optional integration.

# --- Required ----------------------------------------------------------------
# OpenAI Realtime, Responses, and computer-use.
OPENAI_API_KEY=

# Required for Google Cloud Vision OCR/labels.
# Example: /Users/you/.config/gcloud/iris-service-account.json
# --- Local gateway -----------------------------------------------------------
# Bearer token for the local HTTP gateway (`./iris serve`). Generate one with:
# python3 -c 'import secrets; print(secrets.token_urlsafe(32))'
# The macOS app generates its own and keeps it in the Keychain.
IRIS_GATEWAY_TOKEN=
IRIS_STATE_DB=build/iris.sqlite3

# --- Optional integrations ---------------------------------------------------
# Google Cloud Vision OCR/labels. Path to a service-account JSON key, e.g.
# /Users/you/.config/gcloud/iris-service-account.json
GOOGLE_APPLICATION_CREDENTIALS=

# Groq, for low-latency speech-to-text and intent routing (falls back to OpenAI).
GROQ_API_KEY=
IRIS_FAST_INTENT_MODEL=compound-mini
IRIS_STT_MODEL=whisper-large-v3-turbo

# Phone push notifications: pushover (default) or ntfy.
IRIS_NOTIFY_PROVIDER=pushover
PUSHOVER_TOKEN=
PUSHOVER_USER=
IRIS_NTFY_SERVER=https://ntfy.sh
IRIS_NTFY_TOPIC=
IRIS_NTFY_TOKEN=
IRIS_NOTIFY_TIMEOUT_SECONDS=30

# Outbound email via Resend — meeting recaps and the send_email tool.
IRIS_EMAIL_PROVIDER=resend
RESEND_API_KEY=
IRIS_EMAIL_FROM=
IRIS_EMAIL_TO=

# --- Identity & hotkeys ------------------------------------------------------
IRIS_AGENT_NAME=Iris
IRIS_VOICE=marin
IRIS_TOGGLE_HOTKEY=<ctrl>+<space>
IRIS_KILL_HOTKEY=<ctrl>+<alt>+k

# --- Models ------------------------------------------------------------------
IRIS_REALTIME_MODEL=gpt-realtime-2
IRIS_REALTIME_TRANSCRIPTION_MODEL=gpt-4o-mini-transcribe
IRIS_CHAT_MODEL=gpt-5.5
IRIS_VISION_MODEL=gpt-5.5
IRIS_COMPUTER_USE_MODEL=computer-use-preview
IRIS_COMPUTER_USE_ENVIRONMENT=browser
IRIS_EMBEDDING_MODEL=text-embedding-3-small

# --- Memory ------------------------------------------------------------------
IRIS_MEMORY_EMBEDDINGS_ENABLED=true
# local = deterministic offline vectors, openai = API embeddings, auto = OpenAI if configured else local
# local = deterministic offline vectors, openai = API embeddings,
# auto = OpenAI if configured, else local.
IRIS_MEMORY_EMBEDDING_PROVIDER=local
IRIS_COMPUTER_USE_MODEL=computer-use-preview
IRIS_COMPUTER_USE_ENVIRONMENT=browser
GROQ_API_KEY=
IRIS_FAST_INTENT_MODEL=compound-mini
IRIS_STT_MODEL=whisper-large-v3-turbo
IRIS_REALTIME_TRANSCRIPTION_MODEL=gpt-4o-mini-transcribe
IRIS_SCREENSHOT_INTERVAL_SECONDS=0.5
IRIS_GATEWAY_TOKEN=
IRIS_STATE_DB=build/iris.sqlite3

# --- Safety & privacy --------------------------------------------------------
IRIS_AUTONOMY_LEVEL=L1
IRIS_MEETING_CONSENT_REQUIRED=true
IRIS_MEETING_RETENTION_DAYS=30
IRIS_LISTEN_SECONDS=2.0
IRIS_WAKE_POLL_SECONDS=1.2

# --- Voice & turn-taking -----------------------------------------------------
IRIS_WAKE_WORDS=iris,hey iris
IRIS_WAKE_POLL_SECONDS=1.2
IRIS_LISTEN_SECONDS=2.0
IRIS_SCREENSHOT_INTERVAL_SECONDS=0.5
IRIS_BARGE_IN_ENABLED=true
IRIS_BARGE_IN_GRACE_MS=250
IRIS_ECHO_SUPPRESSION_MS=800
Expand All @@ -42,26 +81,15 @@ IRIS_TURN_MAX_WAIT_MS=2500
IRIS_TURN_MIN_WORDS_FOR_IMMEDIATE_RESPONSE=4
IRIS_LIVE_VAD_SILENCE_MS=900
# Only controls terminal fallback output through macOS `say`.
# Live `./iris start --live` speech-to-speech still speaks through Realtime.
# Live `./iris start --live` speech-to-speech always speaks through Realtime.
IRIS_SPEAK_RESPONSES=false
IRIS_MAX_RESPONSE_CHARS=220

# Terminal-first phone push. Pushover is the v1 default. ntfy is still supported.
IRIS_NOTIFY_PROVIDER=pushover
PUSHOVER_TOKEN=
PUSHOVER_USER=
IRIS_NTFY_SERVER=https://ntfy.sh
IRIS_NTFY_TOPIC=
IRIS_NTFY_TOKEN=
IRIS_NOTIFY_TIMEOUT_SECONDS=30

# Outbound email (Resend). Used for meeting recaps and the send_email tool.
IRIS_EMAIL_PROVIDER=resend
RESEND_API_KEY=
IRIS_EMAIL_FROM=
IRIS_EMAIL_TO=

# Advanced profile overrides. Most users should run `./iris setup` instead.
# --- Profile overrides -------------------------------------------------------
# Most users should run `./iris setup` instead.
# IRIS_USER_NAME=
# IRIS_USER_FIRST_NAME=
# IRIS_USER_PRONOUNS=

# --- Tooling -----------------------------------------------------------------
UV_NO_EDITABLE=1
49 changes: 49 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Bug report
description: Something isn't working as expected.
labels: [bug]
body:
- type: markdown
attributes:
value: |
Thanks for the report! Please **don't include API keys, tokens, or
personal data**. Redact logs before pasting. Security issues go through
[private reporting](https://github.com/bethvourc/iris/security/advisories/new) instead.
- type: textarea
id: what-happened
attributes:
label: What happened?
description: What did you do, what did you expect, and what happened instead?
validations:
required: true
- type: textarea
id: repro
attributes:
label: Steps to reproduce
placeholder: |
1. ./iris start --live
2. Say "…"
3. …
validations:
required: true
- type: dropdown
id: surface
attributes:
label: Where does it happen?
options:
- Terminal CLI (./iris)
- macOS app
- Gateway / API
- Other
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
description: Paste the output of `./iris doctor` and `./iris status` (redact anything sensitive).
render: text
- type: input
id: version
attributes:
label: Version or commit
placeholder: v0.1.0 or a commit SHA
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Report a security vulnerability
url: https://github.com/bethvourc/iris/security/advisories/new
about: Please report vulnerabilities privately, not as public issues.
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Feature request
description: Suggest an idea or improvement.
labels: [enhancement]
body:
- type: textarea
id: problem
attributes:
label: What problem would this solve?
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposed solution
description: What should Iris do? If the change touches safety or approvals, say how it stays safe.
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
17 changes: 17 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
groups:
actions:
patterns: ["*"]

- package-ecosystem: uv
directory: /
schedule:
interval: monthly
groups:
python:
patterns: ["*"]
15 changes: 15 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Summary

<!-- What does this change, and why? Link any related issue. -->

## Testing

<!-- How did you verify it? Which tests did you add or update? -->

## Checklist

- [ ] `uv run ruff check src tests` and `uv run pytest -q` pass
- [ ] Swift changes pass `swiftlint --strict`, `swiftformat --lint .`, and the Xcode tests
- [ ] No secrets, tokens, or personal data in code, tests, fixtures, or logs
- [ ] Docs updated (README, `docs/`, `.env.example`) if behavior or config changed
- [ ] Safety-relevant changes (risk tiers, approvals, gateway auth) are called out above
29 changes: 26 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ on:
branches: [main]
pull_request:

# Read-only token: CI never needs to write to the repo, and PRs from forks run
# this workflow with untrusted code.
permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
python:
name: Python daemon
Expand All @@ -27,15 +36,29 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install tools
run: brew install xcodegen swiftlint swiftformat
run: brew install xcodegen swiftlint
# Pinned: new SwiftFormat releases add default-on rules (0.63.0 added
# wrapIfStatementBodies), which would fail every PR on untouched code.
# Bump the version and the checksum together, then reformat in one PR.
- name: Install SwiftFormat (pinned)
env:
SWIFTFORMAT_VERSION: 0.61.1
SWIFTFORMAT_SHA256: b990400779aceb7d7020796eb9ba814d4480543f671d38fc0ff48cb72f04c584
run: |
set -euo pipefail
curl -fsSL -o "$RUNNER_TEMP/swiftformat.zip" \
"https://github.com/nicklockwood/SwiftFormat/releases/download/${SWIFTFORMAT_VERSION}/swiftformat.zip"
echo "${SWIFTFORMAT_SHA256} $RUNNER_TEMP/swiftformat.zip" | shasum -a 256 -c -
unzip -q "$RUNNER_TEMP/swiftformat.zip" -d "$RUNNER_TEMP/swiftformat"
echo "$RUNNER_TEMP/swiftformat" >> "$GITHUB_PATH"
- name: Generate project
run: xcodegen generate
working-directory: apps/macos
- name: SwiftLint
run: swiftlint --strict
working-directory: apps/macos
- name: SwiftFormat (lint only)
run: swiftformat --lint .
run: swiftformat --version && swiftformat --lint .
working-directory: apps/macos
- name: Build and test
run: >
Expand All @@ -48,7 +71,7 @@ jobs:

release-scripts:
name: Release scripts (ad-hoc dry run)
# Exercises the Step 7.2 pipeline logic — embed runtime, inside-out sign,
# Exercises the release pipeline logic — embed runtime, inside-out sign,
# DMG — without any signing secrets, so regressions surface on every PR.
# Single-arch build for speed; universality is covered by the runtime build.
runs-on: macos-15
Expand Down
18 changes: 17 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,26 @@ jobs:
run: |
set -euo pipefail
DMG="${{ steps.dmg.outputs.DMG_PATH }}"
shasum -a 256 "$DMG" | tee "$DMG.sha256"
# Hash the bare filename, not the absolute runner path, so that a
# downloader can `shasum -c Iris-<version>.dmg.sha256` next to the DMG.
( cd "$(dirname "$DMG")" \
&& shasum -a 256 "$(basename "$DMG")" | tee "$(basename "$DMG").sha256" )
echo "SHA256_FILE=$DMG.sha256" >> "$GITHUB_OUTPUT"

# Dry runs (workflow_dispatch) have no tag, and a GitHub Release requires
# one — so publish only on a tag and hand dry runs the DMG as an artifact.
- name: Upload DMG artifact (untagged dry runs)
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
uses: actions/upload-artifact@v4
with:
name: Iris-${{ steps.dmg.outputs.DMG_VERSION }}-dmg
path: |
${{ steps.dmg.outputs.DMG_PATH }}
${{ steps.sums.outputs.SHA256_FILE }}
if-no-files-found: error

- name: Create draft GitHub Release
if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: softprops/action-gh-release@v2
with:
draft: true
Expand Down
40 changes: 33 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
.DS_Store
# --- Secrets & local config -------------------------------------------------
# Real config lives next to the committed *.example templates.
.env
.env.*
!.env.example
mcp.json
*.pem
*.p12
*.p8
*.cer
*.mobileprovision
*.provisionprofile
*.keychain-db
*service-account*.json
apps/macos/Config/*.local.xcconfig

# --- Local state -------------------------------------------------------------
*.sqlite3
*.sqlite3-*
iris-debug/
iris_tmp_exec_test
*.log

# --- Python ------------------------------------------------------------------
.venv/
__pycache__/
*.py[cod]
Expand All @@ -13,12 +33,18 @@ htmlcov/
dist/
build/
*.egg-info/
iris-debug/
iris_tmp_exec_test
*.log
implementation/

# Xcode
# --- Xcode / macOS -----------------------------------------------------------
xcuserdata/
DerivedData/
*.xcresult
*.xcresult
*.dmg
.DS_Store

# --- Editors & tools ---------------------------------------------------------
.idea/
.vscode/
.claude/settings.local.json

# Private working notes
implementation/
Loading
Loading