diff --git a/assets/hero.png b/assets/hero.png
index d469b65..2dd12af 100644
Binary files a/assets/hero.png and b/assets/hero.png differ
diff --git a/assets/hero.svg b/assets/hero.svg
index 0ede983..6258e35 100644
--- a/assets/hero.svg
+++ b/assets/hero.svg
@@ -14,10 +14,12 @@
-
+
-
-
+
+
+
+
diff --git a/assets/social.png b/assets/social.png
index 00c6894..f62d8c9 100644
Binary files a/assets/social.png and b/assets/social.png differ
diff --git a/assets/social.svg b/assets/social.svg
index b7cc3d2..2136248 100644
--- a/assets/social.svg
+++ b/assets/social.svg
@@ -16,8 +16,10 @@
-
-
+
+
+
+
swisscode
diff --git a/src/adapters/agents/kilo/index.ts b/src/adapters/agents/kilo/index.ts
index 44c4960..8cdf2b7 100644
--- a/src/adapters/agents/kilo/index.ts
+++ b/src/adapters/agents/kilo/index.ts
@@ -19,6 +19,7 @@ import {
ambientUnset,
anthropicOptions,
collapsedTierWarning,
+ compatIgnoredWarning,
sessionUnavailableWarning,
extendedContextWarning,
modelRef,
@@ -57,7 +58,7 @@ export const kilo = {
},
binary,
translate(input: TranslateInput): Translation {
- const { intent, passthrough } = input
+ const { intent, passthrough, profile } = input
const primary = intent.models.opus
const config: Record = {
@@ -82,6 +83,8 @@ export const kilo = {
if (collapse) warnings.push(collapse)
const ext = extendedContextWarning(intent, primary, 'Kilo')
if (ext) warnings.push(ext)
+ const compat = compatIgnoredWarning(profile.compat, 'Kilo')
+ if (compat) warnings.push(compat)
return { plan: { set, unset: ambientUnset(intent) }, args: [...passthrough], warnings }
},
diff --git a/src/adapters/agents/opencode/index.ts b/src/adapters/agents/opencode/index.ts
index 17336f0..0b9976b 100644
--- a/src/adapters/agents/opencode/index.ts
+++ b/src/adapters/agents/opencode/index.ts
@@ -16,6 +16,7 @@ import {
ambientUnset,
anthropicOptions,
collapsedTierWarning,
+ compatIgnoredWarning,
sessionUnavailableWarning,
extendedContextWarning,
modelRef,
@@ -56,7 +57,7 @@ export const opencode = {
},
binary,
translate(input: TranslateInput): Translation {
- const { intent, passthrough } = input
+ const { intent, passthrough, profile } = input
const primary = intent.models.opus
const small = intent.models.haiku
@@ -87,6 +88,8 @@ export const opencode = {
if (collapse) warnings.push(collapse)
const ext = extendedContextWarning(intent, primary, 'OpenCode')
if (ext) warnings.push(ext)
+ const compat = compatIgnoredWarning(profile.compat, 'OpenCode')
+ if (compat) warnings.push(compat)
return { plan: { set, unset: ambientUnset(intent) }, args, warnings }
},
diff --git a/src/adapters/agents/shared.ts b/src/adapters/agents/shared.ts
index a41da85..593dffb 100644
--- a/src/adapters/agents/shared.ts
+++ b/src/adapters/agents/shared.ts
@@ -103,6 +103,35 @@ export function collapsedTierWarning(
}
}
+/**
+ * Warn when a profile carries gateway compatibility flags that this agent does
+ * not consume.
+ *
+ * The compat mechanism is Claude-Code-only (capabilities.compatFlags). A flag
+ * toggled on for a Kilo or OpenCode setup changes nothing and, until this
+ * existed, said so NOWHERE — not at edit, not at launch, not in the doctor.
+ * That is the one capability mismatch with no net, and the
+ * capability-gap-never-silently-dropped rule the tier and session warnings
+ * already follow says it should have one. The flags are kept, not stripped, so
+ * the setup still works when it runs Claude Code again.
+ */
+export function compatIgnoredWarning(
+ compat: Record | undefined,
+ agentLabel: string,
+): EnvWarning | null {
+ const active = Object.entries(compat ?? {})
+ .filter(([, on]) => on)
+ .map(([id]) => id)
+ if (active.length === 0) return null
+ return {
+ severity: 'medium',
+ code: 'compat-ignored',
+ message:
+ `${agentLabel} does not use gateway compatibility flags; these are set but ignored: ` +
+ `${active.join(', ')}.`,
+ }
+}
+
/**
* Warn when a 1M-capable provider is reached without Claude Code's `[1m]`
* signal, which only Claude Code sends. The model still runs; its window is
diff --git a/test/adapters/agents/kilo.test.ts b/test/adapters/agents/kilo.test.ts
index 1ddba9a..5e9eb9f 100644
--- a/test/adapters/agents/kilo.test.ts
+++ b/test/adapters/agents/kilo.test.ts
@@ -68,3 +68,35 @@ test('capabilities describe a single model slot', () => {
assert.equal(kilo.binary.name, 'kilo')
assert.equal(kilo.binary.overrideEnv, 'SWISSCODE_KILO_BIN')
})
+
+test('a gateway compat flag on a Kilo profile is flagged as ignored — the safety net', () => {
+ // The UI now hides the compat section for Kilo, but a hand-edited or
+ // agent-switched config can still carry a flag. Compat is Claude-Code-only,
+ // so Kilo warns rather than silently doing nothing — the one mismatch that
+ // previously had no net at edit, launch, or doctor.
+ const input: TranslateInput = {
+ intent: intent(),
+ profile: makeProfile({ provider: 'zai', compat: { disableAdaptiveThinking: true } }),
+ provider: null,
+ passthrough: [],
+ ambient: {},
+ }
+ const w = kilo.translate(input).warnings.find((x) => x.code === 'compat-ignored')
+ assert.ok(w, 'Kilo should warn that a compat flag is ignored')
+ assert.match(w.message, /disableAdaptiveThinking/)
+ assert.match(w.message, /Kilo/)
+})
+
+test('a Kilo profile with no compat flags emits no compat-ignored warning', () => {
+ const input: TranslateInput = {
+ intent: intent(),
+ profile: makeProfile({ provider: 'zai' }),
+ provider: null,
+ passthrough: [],
+ ambient: {},
+ }
+ assert.equal(
+ kilo.translate(input).warnings.find((x) => x.code === 'compat-ignored'),
+ undefined,
+ )
+})
diff --git a/web/index.html b/web/index.html
index 4b1a57d..b0fb415 100644
--- a/web/index.html
+++ b/web/index.html
@@ -4,6 +4,15 @@
swisscode
+
+
+
+
+