<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://doc.expecco.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Sv</id>
	<title>expecco Wiki (Version 26.x) - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://doc.expecco.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Sv"/>
	<link rel="alternate" type="text/html" href="https://doc.expecco.de/wiki/Spezial:Beitr%C3%A4ge/Sv"/>
	<updated>2026-08-25T19:43:18Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31744</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31744"/>
		<updated>2026-08-21T18:19:01Z</updated>

		<summary type="html">&lt;p&gt;Sv: 26.2: native Remote Access SSH/SFTP action blocks (link to main article)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
* Feature: [[ElementaryBlock_Element/en#Scheme_Blocks_(Bridged)|bridged Scheme]] (currently only Racket Scheme) action blocks&lt;br /&gt;
* Feature: [[ElementaryBlock_Element/en#Octave_Blocks_(Bridged)|bridged Octave/Matlab]] action blocks&lt;br /&gt;
* Feature: [[Expecco_API/en#C#_Actions|bridged C#]] action blocks&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; AI Coding provider &amp;quot;&#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039;&amp;quot; — uses your existing Claude subscription via the locally installed &#039;&#039;Claude Code&#039;&#039; command line program instead of an API key, so no key has to be entered and no per-token API charges are billed. Choose it like any other provider in the settings dialog (Plugins → AI Coding); the API key, endpoint URL and proxy fields are hidden for it because they do not apply, and the authentication method reads &amp;quot;Subscription (external login)&amp;quot;. It requires &#039;&#039;Claude Code&#039;&#039; to be installed and logged in once (run &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in a terminal and complete the login). The model is selectable either as a tier alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — always the current model of that tier) or as a pinned model id.&lt;br /&gt;
* Feature: two new AI actions that work on the selected &#039;&#039;&#039;class&#039;&#039;&#039; rather than on a single method, reachable from the &#039;&#039;&#039;AI&#039;&#039;&#039; menu of the class browser: &amp;quot;&#039;&#039;&#039;Explain Class&#039;&#039;&#039;&amp;quot; explains the class as a whole — what it is responsible for, what its instance variables hold and how its protocols fit together — and &amp;quot;&#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039;&amp;quot; proposes a class documentation text which the &amp;quot;[Apply]&amp;quot; button installs into the class&#039; documentation.&lt;br /&gt;
* Feature: HTTP/2 (h2) support in the embedded web server, negotiated via TLS ALPN, with HPACK header compression and request multiplexing over a single connection. Implemented in pure Smalltalk, so no external library is required. This is the server side only — the HTTP client (&#039;&#039;HTTPInterface&#039;&#039;) continues to speak HTTP/1.1. A server configured without a certificate stays on HTTP/1.1, because h2 is negotiated during the TLS handshake; the offer can be turned off with &amp;lt;code&amp;gt;HTTPServer http2Enabled:false&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Feature: ALM repository project version access in the project tree; see versions directly in a second tree (readonly), drag items out of it, execute test plans etc. Create new version and easy commit.&lt;br /&gt;
* Feature: TEAM support; multiple teams users can live-edit the same suite for merge, group development, passing work to other users or demonstration. &lt;br /&gt;
* Feature: improved SSDP service announcement&lt;br /&gt;
* Feature: full ipV6 UDP support (mostly socketAddress fixes and multicast support)&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[SNMP Plugin Reference/en|SNMP]] support, reimplemented in expecco itself - no &#039;&#039;net-snmp&#039;&#039; installation is needed any more, and the blocks behave identically on every supported platform. SNMP v1, v2c and v3 (authentication with MD5, SHA-1 or one of the SHA-2 protocols of RFC 7860, encryption with DES or AES-128); a whole table read by one block with its rows and their INDEX decoded (ifTable, ipAddrTable, tcpConnTable, ...); many devices asked the same question at once, in parallel; traps and informs both received and sent. An up to date set of MIB modules (net-snmp 5.9.5.2) is delivered, so the names of SNMPv2-MIB, IF-MIB, IP-MIB, TCP-MIB and friends resolve out of the box - the deprecated RFC1213-MIB groups (&#039;&#039;at&#039;&#039;, &#039;&#039;egp&#039;&#039;, &#039;&#039;ipRouteTable&#039;&#039;) are not part of it and are shown numerically, add &#039;&#039;RFC1213-MIB.txt&#039;&#039; to a MIB directory (&amp;quot;Add MIB Directory&amp;quot;) if a device still needs those names. Fixes on the way: object identifiers were corrupted on 64bit systems, which made most SNMP blocks return wrong values.&lt;br /&gt;
* Feature: the [[Remote Access/en#From expecco actions|Remote Access]] plugin gained &#039;&#039;&#039;native&#039;&#039;&#039; (pure-Smalltalk, via &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;) SSH and SFTP action blocks — SSH open/close, execute command (with optional stdin), execute a list of commands (each on its own channel or in one persistent shell), password authentication, and SFTP upload (from a file, String or stream), download (to a file and/or a stream, streamed without buffering), list, delete, rename and make-directory; each block ships with a runnable Test/Demo network. No external &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; binary is required.&lt;br /&gt;
* Fix: JSON printer&#039;s recursive store detection was generating false positives&lt;br /&gt;
* Improvement: better Python syntax highlighter&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039;, &#039;&#039;&#039;ollama&#039;&#039;&#039; and others as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via [[Tools_FileBrowser/en|FileBrowser]])&lt;br /&gt;
* Feature: public/private keypair generation via a [[Tools_FileBrowser/en|FileBrowser]] menu (for easy SSH setup)&lt;br /&gt;
* Improvement: Bundled python3 installer updated to version 3.13.14&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed the [[Number_API_Functions|Number]] stack (see also in [[Numeric_Limits/en| Numeric Limits]]):&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. and type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan). Now all test cases produce a result within the precision limits of their type&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]&lt;br /&gt;
* UI: &#039;&#039;&#039;Ctrl-Return&#039;&#039;&#039; now accepts the default action in every modal dialog — both the modern SimpleDialog-based ones (check-in log message, search dialogs, ...) and old-style DialogBox-based ones (EnterBox, OptionBox, InfoBox, ...). Unlike plain Return, Ctrl-Return submits the dialog even when the focus is on a multi-line text editor (which normally keeps Return as a newline), so there is no need to tab off the editor first.&lt;br /&gt;
* UI: Transcript (the console) always appends text at end.&lt;br /&gt;
* UI: Transcript does not scroll to end on incoming text while moving the scrollbar &lt;br /&gt;
* Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
* Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
* Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Performance: speedup of cryptographic algorithms (affects key generation and other)&lt;br /&gt;
* Performance: tuned loading of stored ets/elf files (30-40% speedup)&lt;br /&gt;
* Performance: further speedup when loading test-result archives that embed large execution logs — typical load is roughly a third faster again&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31743</id>
		<title>Remote Access</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31743"/>
		<updated>2026-08-21T18:18:59Z</updated>

		<summary type="html">&lt;p&gt;Sv: native SSH/SFTP-Aktionsbloecke (26.2) unter &amp;#039;Aus expecco-Aktionen&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fernzugriff&#039;&#039;&#039; bezeichnet die Möglichkeit, einen entfernten&lt;br /&gt;
Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus&lt;br /&gt;
zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu&lt;br /&gt;
verschieben oder ein Testgerät anzusteuern.  Drei Protokoll-Familien&lt;br /&gt;
sind unterstützt, in absteigender Empfehlungsreihenfolge:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH und SFTP&#039;&#039;&#039; (empfohlen) — verschlüsselte Shell und sichere Dateiübertragung über einen SSH-2-Tunnel.  Reine Smalltalk-Implementierung in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; keine externe Abhängigkeit von OpenSSL oder libssh.  Für alles mit Zugangsdaten oder sensiblen Nutzdaten.&lt;br /&gt;
* &#039;&#039;&#039;Lokale Kommando-Shell&#039;&#039;&#039; — fork + exec auf der lokalen Maschine.  Für die Anbindung lokaler Werkzeuge und für die lokale Seite eines hybriden Workflows.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (veraltet) — Klartext-Terminalsitzung.  Keine Verschlüsselung, Passwörter im Klartext auf der Leitung.  Nur einsetzen, wenn die Gegenstelle keine Alternative bietet.&lt;br /&gt;
&lt;br /&gt;
= SSH und SFTP =&lt;br /&gt;
&lt;br /&gt;
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab&lt;br /&gt;
(RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der&lt;br /&gt;
chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das&lt;br /&gt;
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02).  Zwei Schichten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatischer SSH-Zugriff (entferntes &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY-Shell, Agent-Weiterleitung, ProxyJump-Bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — eine&lt;br /&gt;
&amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;-Unterklasse, die es dem restlichen ST/X&lt;br /&gt;
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale&lt;br /&gt;
Datei.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut:&lt;br /&gt;
zuerst das, was der Anwender sieht und tut, darunter die&lt;br /&gt;
expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails&lt;br /&gt;
für Interessierte.&lt;br /&gt;
&lt;br /&gt;
== Aus dem FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Im Adress-Dropdown eine &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt;-URL einfügen.  Der&lt;br /&gt;
Browser-Tab füllt sich wie bei einem lokalen Pfad.&lt;br /&gt;
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),&lt;br /&gt;
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich&lt;br /&gt;
normal.  Der erste Klick auf einen Host dauert ~200–500 ms&lt;br /&gt;
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte&lt;br /&gt;
Verbindung weiter.&lt;br /&gt;
&lt;br /&gt;
URL-Syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user[:password]@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlt &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;, wird der lokale Login-Name verwendet, Port&lt;br /&gt;
ist standardmäßig 22, Pfad standardmäßig &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.  Das&lt;br /&gt;
optionale &amp;lt;code&amp;gt;:password&amp;lt;/code&amp;gt;-Segment ist das RFC-3986-Userinfo-Passwort&lt;br /&gt;
&amp;amp;mdash; wann es angebracht ist und welche Sicherheitsabwägungen&lt;br /&gt;
damit verbunden sind, beschreibt [[#Passwort-Authentifizierung]].&lt;br /&gt;
Wenn vorhanden, dient es als USERAUTH-Fallback nach den üblichen&lt;br /&gt;
Publickey-/Agent-Versuchen und wird &#039;&#039;&#039;niemals&#039;&#039;&#039; wieder von der&lt;br /&gt;
druckbaren URL-Form ausgegeben &amp;amp;mdash; das Protokollieren des&lt;br /&gt;
Dateinamens leakt also nicht das Credential.&lt;br /&gt;
&lt;br /&gt;
Die Schaltfläche &#039;&#039;&#039;Refresh&#039;&#039;&#039; in der Symbolleiste&lt;br /&gt;
(Pfeil-Kreis-Symbol zwischen &#039;&#039;Forward&#039;&#039; und &#039;&#039;DirectoryUp&#039;&#039;) liest&lt;br /&gt;
Baum und Inhalts-Panel auf Anforderung neu ein.  Funktioniert&lt;br /&gt;
einheitlich für lokale und SFTP-Pfade; bei SFTP wird zusätzlich der&lt;br /&gt;
per-Datei-STAT-Cache geleert, sodass Änderungen, die direkt auf&lt;br /&gt;
der Gegenseite gemacht wurden, sofort sichtbar werden — ohne auf&lt;br /&gt;
den Ablauf der 5-Sekunden-Cache-TTL zu warten.&lt;br /&gt;
&lt;br /&gt;
Der kleine Pfeil neben dem Refresh-Symbol öffnet ein Aufklappmenü&lt;br /&gt;
mit einem einzelnen Kontrollkästchen, &#039;&#039;&#039;Automatic Refresh&#039;&#039;&#039;, das&lt;br /&gt;
den Hintergrund-Task an- bzw. abschaltet, der alle expandierten&lt;br /&gt;
Baumeinträge auf externe Änderungen prüft.  Die Vorgabe richtet&lt;br /&gt;
sich nach der aktuellen Wurzel:&lt;br /&gt;
&lt;br /&gt;
* Lokales Dateisystem &amp;amp;rarr; &#039;&#039;&#039;an&#039;&#039;&#039; (10-Sekunden-Zyklus, entspricht dem bisherigen Verhalten).&lt;br /&gt;
* SFTP &amp;amp;rarr; &#039;&#039;&#039;aus&#039;&#039;&#039;.  Jeder Zyklus kostet einen STAT-Roundtrip pro Kind — für eine Handvoll lokaler Verzeichnisse harmlos, über das Netz schmerzhaft.  Bei Bedarf manuell auf Refresh klicken, um Änderungen zu sehen.&lt;br /&gt;
&lt;br /&gt;
Beim Wechsel zwischen lokalen und SFTP-Wurzeln wird der Schalter&lt;br /&gt;
automatisch umgelegt &amp;amp;mdash; aber nur, sofern man ihn für die&lt;br /&gt;
vorherige Wurzel nicht selbst verstellt hat.  Eine explizite&lt;br /&gt;
Benutzerwahl bleibt über Navigationen hinweg erhalten.&lt;br /&gt;
&lt;br /&gt;
Das Menü &#039;&#039;&#039;Tools&#039;&#039;&#039; im FileBrowserV2 bietet vier Aktionen — die&lt;br /&gt;
drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek&lt;br /&gt;
sichtbar:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — öffnet den Schlüsselerzeugungs-Dialog, siehe [[#Einen SSH-Schlüssel erzeugen]] unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — öffnet ein interaktives VT100-Terminal zu einem entfernten Host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — navigiert diesen Browser-Tab über SFTP auf ein entferntes Dateisystem.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — zeigt Größe, freien Platz und Belegung des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP setzt der Aufruf voraus, daß der Server die Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; ankündigt (jedes moderne OpenSSH&lt;br /&gt;
tut das).  Größen werden in IEC-Binäreinheiten ausgegeben (MiB,&lt;br /&gt;
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1&lt;br /&gt;
liefert, damit ein TB-großes Volume als &#039;&#039;X TiB&#039;&#039; statt&lt;br /&gt;
&#039;&#039;10240 GiB&#039;&#039; erscheint.&lt;br /&gt;
&lt;br /&gt;
== Aus dem Launcher ==&lt;br /&gt;
&lt;br /&gt;
Das Untermenü &#039;&#039;&#039;Workspace&#039;&#039;&#039; im Launcher enthält zwei eigenständige&lt;br /&gt;
Einträge (nur sichtbar bei geladenem SSH-Paket):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH Terminal&#039;&#039;&#039; &amp;amp;mdash; fragt nach einem Ziel der Form &amp;lt;code&amp;gt;user[:password]@host[:port]&amp;lt;/code&amp;gt; und öffnet ein VT100-Terminal als eigenständiges Fenster.  Das ist das Launcher-Pendant zum FileBrowserV2-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; SSH Connect...&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connection&#039;&#039;&#039; &amp;amp;mdash; fragt nach einem SFTP-Ziel (gleiche URL-Grammatik wie in der FileBrowserV2-Adresszeile, siehe [[#Aus dem FileBrowserV2]]) und öffnet einen frischen FileBrowserV2, der bereits dorthin navigiert ist.&lt;br /&gt;
&lt;br /&gt;
Beide Einträge unterstützen die in [[#Passwort-Authentifizierung]]&lt;br /&gt;
beschriebene URL-Form mit eingebettetem Passwort.&lt;br /&gt;
&lt;br /&gt;
== Aus expecco-Aktionen ==&lt;br /&gt;
&lt;br /&gt;
Das Expecco-RemoteAccess-Plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) stellt folgende Testaktionen&lt;br /&gt;
in der expecco-Aktionspalette bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — öffnet eine SSH-Sitzung über das plattformeigene &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;-Binary (PuTTYs &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; unter Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.&lt;br /&gt;
&lt;br /&gt;
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater&lt;br /&gt;
Schlüssel auf dieser Maschine, öffentlicher Teil in der&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des Zielhosts).  Schlüssel&lt;br /&gt;
erzeugen entweder über den Dialog unten oder über&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Plugin fügt zusätzlich eine Settings-Seite hinzu:&lt;br /&gt;
&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039; mit&lt;br /&gt;
einer einzelnen Schaltfläche &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039;, die&lt;br /&gt;
denselben Dialog öffnet.&lt;br /&gt;
&lt;br /&gt;
Seit expecco 26.2 stellt das Plugin zusätzlich &#039;&#039;&#039;native&#039;&#039;&#039; SSH- und SFTP-Aktionsblöcke bereit, in reinem Smalltalk auf Basis von &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt; implementiert — kein externes &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;- oder &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt;-Binary erforderlich.  Eine Verbindung wird einmal geöffnet und ihr &amp;lt;code&amp;gt;SshHandle&amp;lt;/code&amp;gt; an die folgenden Blöcke weitergereicht.&lt;br /&gt;
&lt;br /&gt;
SSH-Blöcke:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH - Open Connection&#039;&#039;&#039; — verbinden und authentifizieren (expliziter privater Schlüssel, ssh-agent oder die Standard-Schlüssel in &amp;lt;code&amp;gt;~/.ssh&amp;lt;/code&amp;gt;); liefert ein &amp;lt;code&amp;gt;SshHandle&amp;lt;/code&amp;gt; für die Blöcke unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Open Connection with Password&#039;&#039;&#039; — dasselbe, jedoch mit Klartext-Passwort statt eines Schlüssels.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Execute Command&#039;&#039;&#039; — führt ein einzelnes Kommando aus; liefert stdout, stderr und Exit-Status, mit einem optionalen stdin-Stream, der an den entfernten Prozess geleitet wird.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Execute Commands&#039;&#039;&#039; — führt eine Liste von Kommandos aus, jedes als eigener Exec-Kanal, auf einer offenen Verbindung.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Execute Commands In Shell&#039;&#039;&#039; — führt eine Liste von Kommandos in einer einzigen, dauerhaften Login-Shell aus, sodass Zustand wie das Arbeitsverzeichnis über die Kommandos hinweg erhalten bleibt.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Close Connection&#039;&#039;&#039; — schließt eine oben geöffnete Verbindung.&lt;br /&gt;
&lt;br /&gt;
SFTP-Blöcke (jeweils auf einem offenen &amp;lt;code&amp;gt;SshHandle&amp;lt;/code&amp;gt; aufsetzend):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP - Upload File&#039;&#039;&#039; und &#039;&#039;&#039;SFTP - Upload File from String/Stream&#039;&#039;&#039; — schreibt eine lokale Datei bzw. Inhalt aus dem Speicher / einen Read-Stream auf einen entfernten Pfad (gestreamt, ohne die ganze Datei zu puffern).&lt;br /&gt;
* &#039;&#039;&#039;SFTP - Download File&#039;&#039;&#039; — liest eine entfernte Datei in eine lokale Datei und/oder in einen übergebenen Write-Stream (gestreamt, ohne die ganze Datei zu puffern).&lt;br /&gt;
* &#039;&#039;&#039;SFTP - List Directory&#039;&#039;&#039; — listet die Einträge eines entfernten Verzeichnisses auf.&lt;br /&gt;
* &#039;&#039;&#039;SFTP - Delete File&#039;&#039;&#039;, &#039;&#039;&#039;SFTP - Rename&#039;&#039;&#039; und &#039;&#039;&#039;SFTP - Make Directory&#039;&#039;&#039; — Verwaltung entfernter Dateien.&lt;br /&gt;
&lt;br /&gt;
Jeder dieser Blöcke bringt ein lauffähiges Test/Demo-Netz (in seinem &#039;&#039;Test/Demo&#039;&#039;-Reiter) mit, das sich mit dem Host aus den Umgebungsvariablen &amp;lt;code&amp;gt;DEMO_SSH_HOST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DEMO_SSH_PORT&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;DEMO_SSH_USER&amp;lt;/code&amp;gt; verbindet.&lt;br /&gt;
&lt;br /&gt;
== Einen SSH-Schlüssel erzeugen ==&lt;br /&gt;
&lt;br /&gt;
=== Der Dialog (FileBrowserV2 / Settings-Seite) ===&lt;br /&gt;
&lt;br /&gt;
Der Dialog fragt alle Parameter in einem Formular ab:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — wird in den erzeugten Schlüssel eingebettet (Voreinstellung &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — schreibt&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (oder wohin man will) samt&lt;br /&gt;
zugehöriger &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;-Datei daneben.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — schreibt die Datei UND übergibt den Schlüssel dem laufenden ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — der Schlüssel lebt nur im Speicher des Agents; nach Agent-Neustart ist er verloren.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — vollständiger Pfad; ausgegraut im Agent-only-Modus.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — leer lässt die On-Disk-Datei unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten Schlüssel transportiert).&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;Generate&#039;&#039;&#039; wird die Public-Key-Zeile (dieselbe&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt;-Zeichenfolge, die&lt;br /&gt;
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum&lt;br /&gt;
direkten Einfügen in die &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des&lt;br /&gt;
Zielhosts.&lt;br /&gt;
&lt;br /&gt;
=== Aus einem Workspace ===&lt;br /&gt;
&lt;br /&gt;
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; einen reinen Smalltalk-Schlüsselgenerator&lt;br /&gt;
bereit, dessen Ausgabe bit-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt; ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Passphrase-verschlüsselt auf Platte speichern&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ UND in den laufenden Agent laden&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll&lt;br /&gt;
interoperabel (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; rekonstruiert den&lt;br /&gt;
öffentlichen Schlüssel, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; ändert&lt;br /&gt;
die Passphrase usw.).&lt;br /&gt;
&lt;br /&gt;
=== Mit den Shell-Werkzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der klassische Weg funktioniert weiterhin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ssh-agent vorbereiten ==&lt;br /&gt;
&lt;br /&gt;
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien&lt;br /&gt;
deutlich vorzuziehen: er hält verschlüsselte private Schlüssel&lt;br /&gt;
einmal pro Sitzung entsperrt und kann Identitäten verwalten&lt;br /&gt;
(hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X&lt;br /&gt;
nie direkt sehen soll.&lt;br /&gt;
&lt;br /&gt;
ST/X erkennt den Agent-Pfad automatisch, sobald&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;zum Zeitpunkt des Starts von stx&#039;&#039;&#039;&lt;br /&gt;
in der Prozessumgebung gesetzt ist.  Eine spätere Zuweisung aus&lt;br /&gt;
einem Workspace nützt nichts.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Die meisten Desktop-Distributionen starten einen Agent automatisch&lt;br /&gt;
beim Login (gnome-keyring unter GNOME, ssh-agent.service unter&lt;br /&gt;
systemd, KWallet unter KDE).  Prüfen im Terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh oder ähnlich&lt;br /&gt;
ssh-add -l             # listet geladene Identitäten&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # eigene laden, falls nicht da&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei&lt;br /&gt;
aufnehmen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc oder ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X muss aus einer Shell gestartet werden, die diese rc bereits&lt;br /&gt;
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die&lt;br /&gt;
Variable nicht.  Empfehlung: ein kleines Wrapper-Skript unter&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt;, das die rc sourcet und dann stx&lt;br /&gt;
startet.&lt;br /&gt;
&lt;br /&gt;
Die Settings-Seite (&#039;&#039;&#039;Extras → Settings → Plugins → Remote&lt;br /&gt;
Access — SSH Keys&#039;&#039;&#039;) zeigt an, ob das laufende Image einen&lt;br /&gt;
Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Permanente Einrichtung via systemd ====&lt;br /&gt;
&lt;br /&gt;
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-&lt;br /&gt;
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den&lt;br /&gt;
meisten Distros mit dem Paket &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
ausgelieferte Per-User-systemd-Unit aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; in der Shell-rc auf den&lt;br /&gt;
User-Service-Socket zeigen lassen (ersetzt das&lt;br /&gt;
&amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;-Snippet oben):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Um den manuellen &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt;-Schritt zu sparen, kann&lt;br /&gt;
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.&lt;br /&gt;
In &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt; eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und&lt;br /&gt;
übergibt den entsperrten Schlüssel an den Agent; weitere&lt;br /&gt;
Verbindungen nutzen die gespeicherte Identität ohne Prompt.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit.&lt;br /&gt;
Einmalige Einrichtung:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Dienste&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) als Administrator öffnen.&lt;br /&gt;
# &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039; suchen, Starttyp auf &#039;&#039;&#039;Automatisch&#039;&#039;&#039; setzen, &#039;&#039;&#039;Starten&#039;&#039;&#039; anklicken.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Prüfen: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), nicht auf einem&lt;br /&gt;
Unix-Socket.  ST/X unterstützt beide Transporte, jedoch setzt das&lt;br /&gt;
Windows-ssh-add &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; selbst.&lt;br /&gt;
Daher einmalig systemweit setzen:&lt;br /&gt;
&lt;br /&gt;
# {{Key|Win}} drücken → &amp;quot;Umgebungsvariablen&amp;quot; → „Systemumgebungs- variablen bearbeiten&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Umgebungsvariablen&#039;&#039;&#039; → unter &#039;&#039;&#039;Benutzervariablen&#039;&#039;&#039;, &#039;&#039;&#039;Neu&#039;&#039;&#039; klicken.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Wert: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ab- und wieder anmelden (oder stx neu starten), damit die neue Umgebung übernommen wird.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell-Schnelleinrichtung ====&lt;br /&gt;
&lt;br /&gt;
Derselbe Aufbau aus einer &#039;&#039;&#039;Administrator-PowerShell&#039;&#039;&#039; heraus,&lt;br /&gt;
z.B. für Skripte oder unbeaufsichtigte Bereitstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Agent jetzt und bei jedem Neustart starten (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung&lt;br /&gt;
(z.B. Einzelsitzung) die &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt;-Zeile weglassen&lt;br /&gt;
und nur &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt; ausführen.  Die&lt;br /&gt;
env-var-Zeile lässt sich ebenfalls weglassen, wenn&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; nur in der aktuellen Shell gebraucht&lt;br /&gt;
wird — dann statt der &amp;lt;code&amp;gt;[Environment]&amp;lt;/code&amp;gt;-Variante&lt;br /&gt;
&amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Auf stark abgespeckten Windows-Installationen ist der&lt;br /&gt;
ssh-agent-Dienst eventuell nicht vorhanden.  Einmalig nachrüsten&lt;br /&gt;
über &#039;&#039;&#039;Einstellungen → Apps → Optionale Features → OpenSSH-&lt;br /&gt;
Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative Agenten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — eigenes Protokoll; von ST/X&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Agent&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; unterstützt.  Schlüssel zu&lt;br /&gt;
OpenSSH migrieren.&lt;br /&gt;
* &#039;&#039;&#039;Git für Windows ssh-agent&#039;&#039;&#039; — funktioniert;&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; auf den dort veröffentlichten Socket&lt;br /&gt;
zeigen lassen.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — ein ST/X innerhalb der WSL sieht den WSL-eigenen Agent normal; ein ST/X auf der Windows-Seite nicht.  Eine Brücke per &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt; ist möglich.&lt;br /&gt;
&lt;br /&gt;
Prüfung über die Settings-Seite&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
die Anzeige dort meldet, ob das laufende Image den Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Windows-OpenSSH speichert agent-geladene Schlüssel &#039;&#039;&#039;nicht&#039;&#039;&#039;&lt;br /&gt;
über Agent-Neustarts hinweg.  Um nicht nach jedem Reboot manuell&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; aufrufen zu müssen, dieselbe Lazy-Load-&lt;br /&gt;
Konfiguration in &amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;&lt;br /&gt;
eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent&lt;br /&gt;
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige&lt;br /&gt;
Sitzung weiter.&lt;br /&gt;
&lt;br /&gt;
== Passwort-Authentifizierung ==&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist Public-Key-Authentifizierung (mit oder ohne&lt;br /&gt;
ssh-agent).  Passwort-Authentifizierung ist als Fallback gedacht,&lt;br /&gt;
wenn keine Schlüssel verfügbar sind: Altsysteme, Ad-hoc-Zugriff&lt;br /&gt;
auf einen Testserver, Skripte gegen ein Konto, dessen Besitzer den&lt;br /&gt;
Public Key nicht hinterlegen möchte.  Zu beachten:&lt;br /&gt;
&lt;br /&gt;
* Das Klartext-Passwort liegt auf ST/X-Seite für die Lebensdauer des &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; im Speicher &amp;amp;mdash; entsprechend behandeln wie jedes andere In-Memory-Geheimnis.&lt;br /&gt;
* Der Server entscheidet, welche Methoden er akzeptiert.  Steht in &amp;lt;code&amp;gt;sshd_config&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;PasswordAuthentication no&amp;lt;/code&amp;gt;, kann keine Smalltalk-seitige Einstellung das überschreiben.&lt;br /&gt;
* Auf Drahtebene entspricht der Vorgang RFC 4252 §8: das Passwort wandert innerhalb der verschlüsselten SSH-Transportschicht, niemals im Klartext über das Netz.&lt;br /&gt;
&lt;br /&gt;
=== Aus einer URL ===&lt;br /&gt;
&lt;br /&gt;
Sowohl die FileBrowserV2-Adressleiste als auch die Launcher-Dialoge&lt;br /&gt;
&#039;&#039;&#039;Workspace &amp;amp;rarr; SFTP Connection&#039;&#039;&#039; / &#039;&#039;&#039;Workspace &amp;amp;rarr; SSH&lt;br /&gt;
Terminal&#039;&#039;&#039; akzeptieren ein eingebettetes Passwort an der&lt;br /&gt;
standardmäßigen RFC-3986-Userinfo-Position:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://alice:s3cret@host.example.com/srv/data&lt;br /&gt;
ssh   alice:s3cret@host.example.com:2222&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Parser splittet am &#039;&#039;&#039;letzten&#039;&#039;&#039; &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt;, sodass&lt;br /&gt;
Passwörter mit enthaltenem &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; dennoch korrekt geparst&lt;br /&gt;
werden; der erste &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; im Userinfo-Teil trennt Benutzer&lt;br /&gt;
und Passwort.  Passwörter, die selbst ein &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; enthalten,&lt;br /&gt;
werden in dieser Form nicht unterstützt &amp;amp;mdash; dafür die&lt;br /&gt;
programmatische API unten verwenden.&lt;br /&gt;
&lt;br /&gt;
Das Passwort wird aus der druckbaren URL entfernt: jede Stelle, die&lt;br /&gt;
am Ende den Dateinamen ausgibt (Statuszeile,&lt;br /&gt;
&amp;lt;code&amp;gt;printOn:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nameString&amp;lt;/code&amp;gt;, die Breadcrumb-Leiste)&lt;br /&gt;
zeigt die credential-freie Form&lt;br /&gt;
&amp;lt;code&amp;gt;sftp://alice@host.example.com/...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Aus Code ===&lt;br /&gt;
&lt;br /&gt;
Zwei äquivalente Wege, einem &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; ein Passwort&lt;br /&gt;
mitzugeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;/ Literal -- am einfachsten, Passwort ist nur ein Ivar&lt;br /&gt;
client := SSH::Client newToHost:&#039;host.example.com&#039; port:22 user:&#039;alice&#039;.&lt;br /&gt;
client password:&#039;s3cret&#039;.&lt;br /&gt;
client connect.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;/ Callback -- lazy; das Passwort lebt nie auf dem Client.&lt;br /&gt;
&amp;quot;/ Praktisch für interaktive Abfrage, Keychain-Lookup oder ein&lt;br /&gt;
&amp;quot;/ Vault-gespeichertes Geheimnis, das nicht langlebig im Speicher&lt;br /&gt;
&amp;quot;/ liegen soll.&lt;br /&gt;
client passwordCallback:[ Dialog requestPassword:&#039;SSH-Passwort&#039; ].&lt;br /&gt;
client connect.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sind beide gesetzt, gewinnt der Callback.  Beide werden lazy&lt;br /&gt;
während &amp;lt;code&amp;gt;#connect&amp;lt;/code&amp;gt; ausgewertet, nachdem die&lt;br /&gt;
Publickey-/Agent-Versuche abgelehnt wurden &amp;amp;mdash; ein&lt;br /&gt;
funktionierender Schlüssel schlägt also immer ein parallel&lt;br /&gt;
konfiguriertes Passwort.&lt;br /&gt;
&lt;br /&gt;
=== Reihenfolge der Authentifizierungsversuche ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;amp;gt;&amp;amp;gt;authenticate&amp;lt;/code&amp;gt; geht jedes verfügbare&lt;br /&gt;
Credential der Reihe nach durch und kehrt beim ersten zurück, das&lt;br /&gt;
der Server akzeptiert:&lt;br /&gt;
&lt;br /&gt;
# ssh-agent-Identitäten, sofern &amp;lt;code&amp;gt;#useAgent&amp;lt;/code&amp;gt; aufgerufen wurde und der Agent Schlüssel geladen hat.&lt;br /&gt;
# ed25519-Privatschlüssel-Seed, sofern &amp;lt;code&amp;gt;#privateKeyFromFile:&amp;lt;/code&amp;gt; einen geladen hat.&lt;br /&gt;
# RSA-Privatschlüssel.&lt;br /&gt;
# ECDSA-Privatschlüssel.&lt;br /&gt;
# Passwort, sofern &amp;lt;code&amp;gt;#password:&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;#passwordCallback:&amp;lt;/code&amp;gt; gesetzt ist &#039;&#039;&#039;und&#039;&#039;&#039; der Server &amp;lt;code&amp;gt;password&amp;lt;/code&amp;gt; in seiner USERAUTH_FAILURE-Methodenliste weiterhin anbietet.&lt;br /&gt;
&lt;br /&gt;
Jeder Schritt wird übersprungen, wenn die letzte&lt;br /&gt;
&amp;lt;code&amp;gt;USERAUTH_FAILURE&amp;lt;/code&amp;gt;-Antwort des Servers die jeweilige&lt;br /&gt;
Methode aus der erlaubten Liste gestrichen hat &amp;amp;mdash; auf&lt;br /&gt;
&amp;lt;code&amp;gt;publickey&amp;lt;/code&amp;gt; wird also nicht weiter herumgehämmert,&lt;br /&gt;
sobald der Server damit aufhört.  Der Passwortversuch läuft nur,&lt;br /&gt;
wenn der Server &amp;lt;code&amp;gt;password&amp;lt;/code&amp;gt; noch verlangt; ein falsch&lt;br /&gt;
konfiguriertes Passwort gegen einen reinen Schlüssel-Server erzeugt&lt;br /&gt;
also einen sauberen &amp;lt;code&amp;gt;SSH::AuthenticationError&amp;lt;/code&amp;gt; ohne&lt;br /&gt;
zusätzlichen nutzlosen Roundtrip.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Alle Stellschrauben sind klassenseitig auf&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; erreichbar:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Voreinstellung !! Steuert&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 Min) || Wie lange&lt;br /&gt;
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.&lt;br /&gt;
Liegt knapp unter dem typischen&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; des sshd,&lt;br /&gt;
damit wir uns recyceln, bevor der Server uns mit TCP-RESET&lt;br /&gt;
trennt.  &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; setzt auf Voreinstellung zurück.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Maximales Alter (s)&lt;br /&gt;
eines gecachten STAT, bevor &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; neu am&lt;br /&gt;
Server fragt.  Eltern-listDir stempelt ohnehin frische Attribute&lt;br /&gt;
auf alle Kinder, daher zahlt das Navigieren im offenen&lt;br /&gt;
Verzeichnis das TTL nicht.  &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; schaltet den Cache&lt;br /&gt;
ab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (Aktion) || Reißt jede&lt;br /&gt;
gepoolte Verbindung ab.  Nützlich nach einem bekannt schlechten&lt;br /&gt;
Netzereignis, vor einem bewussten Identitätswechsel oder zum&lt;br /&gt;
sauberen Image-Shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnose ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; über das Untermenü „Status&amp;quot; des&lt;br /&gt;
Launchers öffnen.  Der pro-Host-SFTP-Mutex erscheint als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;, der pool-weite Mutex als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Per Rechtsklick:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — schreibt den Walkback des letzten Eigners samt aller Waiter als Text in die Zwischenablage.  Unverzichtbar, wenn ein Prozess in&lt;br /&gt;
&amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; innerhalb von&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; klemmt.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — die ganze Tabelle, ideal für eine E-Mail-Diagnose.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS über den Wait-for-Graph, meldet Zyklen.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
Interessante Ereignisse werden über &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; geloggt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei automatischem Reconnect nach toter Verbindung.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei Idle-Verdrängung eines Pool-Eintrags.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; wenn eine SSH-Schlüsseldatei nicht geparst werden konnte — die Datei wird übersprungen.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nur SFTP v3.&#039;&#039;&#039;  Kein SETSTAT (kein entferntes chmod / chown / utime), kein SSH_FXP_READLINK exponiert (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; liefert immer &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; die normale stat-Info).  Einige&lt;br /&gt;
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische&lt;br /&gt;
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host.&#039;&#039;&#039;  Zwei gleichzeitige Operationen am selben Host stehen am Host-Mutex an.  Siehe [[#Ausblick]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt;-Fallback hat ein TOCTOU-Fenster.&#039;&#039;&#039; Bei Servern, die &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; ankündigen (jedes moderne OpenSSH tut das), ist das Überschreiben atomar. Beim seltenen Server, der das nicht tut, wird auf Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich dazwischenschieben.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; ist eine Heuristik.&#039;&#039;&#039; Liefert immer &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (die genaue Antwort würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).&lt;br /&gt;
&lt;br /&gt;
== Implementierungsdetails ==&lt;br /&gt;
&lt;br /&gt;
Für Leser, die die Architektur verstehen wollen.  Fünf Klassen,&lt;br /&gt;
von oben nach unten:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Aufgabe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename-Unterklasse, die&lt;br /&gt;
öffentliche API.  Bildet &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt;-URLs auf&lt;br /&gt;
entfernte Dateien ab und stellt &amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; usw. bereit.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3-Protokoll&lt;br /&gt;
(Request/Response-Codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Wird von SftpFilename angesteuert.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH-Kanal-Multiplexer (CHANNEL_OPEN,&lt;br /&gt;
DATA, EOF, CLOSE, WINDOW_ADJUST).  Eine logische Sitzung pro&lt;br /&gt;
Channel-Instanz.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-Level-SSH-Client: öffnet den&lt;br /&gt;
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und&lt;br /&gt;
verteilt anschließend Kanäle.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Drahtschicht.  Banner- und&lt;br /&gt;
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq /&lt;br /&gt;
recvSeq, Heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH-SFTP-Erweiterungen ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst&lt;br /&gt;
minimal gehalten.  OpenSSH bringt einen offenen&lt;br /&gt;
Erweiterungsmechanismus mit: der Server listet im&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;-Reply die Erweiterungsnamen auf, die&lt;br /&gt;
er versteht, und der Client ruft sie über&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt;-Pakete mit dem&lt;br /&gt;
Erweiterungsnamen als erstem String auf.  Jede Erweiterung wird&lt;br /&gt;
über &amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;&lt;br /&gt;
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie&lt;br /&gt;
nicht ankündigt.&lt;br /&gt;
&lt;br /&gt;
Der Stack nutzt heute vier OpenSSH-Erweiterungen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomares rename-mit-Überschreiben.  Wird automatisch von&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt; aufgegriffen; die&lt;br /&gt;
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum&lt;br /&gt;
Einsatz, die die Erweiterung nicht haben.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — Erzeugt einen POSIX-Hardlink. Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX-&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-typische Dateisystem-Statistik.&lt;br /&gt;
Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;;&lt;br /&gt;
das Ergebnis ist form-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;, sodass Aufrufer&lt;br /&gt;
lokale und entfernte Pfade einheitlich behandeln können.&lt;br /&gt;
Treibt den Menü-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; an,&lt;br /&gt;
der am Anfang dieser Seite beschrieben ist.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — schreibt den serverseitigen Schreibpuffer eines geöffneten Handles auf Platte.  Liegt als&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt; bereit; noch nicht&lt;br /&gt;
in eine &amp;quot;Durable-Write&amp;quot;-API auf Filename-Ebene eingebunden.&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden OpenSSH-Erweiterungen&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
werden in der angekündigten Liste erkannt, aber nicht auf&lt;br /&gt;
Filename-Ebene gekapselt — es gibt dafür noch keinen&lt;br /&gt;
Filename-seitigen Aufrufer.&lt;br /&gt;
&lt;br /&gt;
=== Verbindungs-Pooling ===&lt;br /&gt;
&lt;br /&gt;
Alle &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt;-Instanzen, die auf dasselbe Tripel&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; zeigen, teilen sich einen&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; samt einem &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Der Pool ist klassenseitig und wird von einem einzigen&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt; bewacht:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy-Aufbau&#039;&#039;&#039; — TCP + KEX + userauth + SFTP-INIT laufen erst beim ersten SFTP-Aufruf, nicht in &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host&#039;&#039;&#039; — SFTP-Anfragen an einen bestimmten Host werden durch einen &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; mit dem Namen &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; serialisiert (sichtbar im SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle-Verdrängung&#039;&#039;&#039; — ein Pool-Eintrag, der länger als&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt; ungenutzt liegt, wird beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet.&lt;br /&gt;
* &#039;&#039;&#039;Automatischer Reconnect&#039;&#039;&#039; — ein Fehler auf Transportebene (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den Pool-Eintrag, öffnet einen frischen Client und wiederholt die Anfrage &#039;&#039;&#039;einmal&#039;&#039;&#039;.  Anwendungsfehler aus SFTP-STATUS-Antworten werden sofort durchgereicht.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
&lt;br /&gt;
Geplant, aber noch nicht umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-Channel-Parallelität pro Host&#039;&#039;&#039; — aktuell bedeutet eine TCP- plus eine SFTP-Verbindung pro Host, dass N gleichzeitige Anfragen serialisieren.  Pipelining über mehrere SshClients im Pool (bevorzugt) oder ein transport-seitiger Reader-Prozess, der eingehende Pakete in Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel erlauben, weiter aufzulisten, während das Inhalts-Panel eine große Datei liest.&lt;br /&gt;
* &#039;&#039;&#039;Genaues &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen kann.&lt;br /&gt;
* &#039;&#039;&#039;SFTP-v5/v6-Aushandlung&#039;&#039;&#039; für erweiterte Attribute und FTP-artige Kanonisierung.  (Atomares Überschreibungs-rename ist bereits über die OpenSSH-Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; abgedeckt; siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]].)&lt;br /&gt;
&lt;br /&gt;
= Kommando-Shell =&lt;br /&gt;
&lt;br /&gt;
Lokale Kommando-Shell auf dieser expecco-Maschine.  Typische&lt;br /&gt;
Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm,&lt;br /&gt;
Brücke zwischen entferntem Workflow und lokalem Tool.&lt;br /&gt;
&lt;br /&gt;
Das RemoteAccess-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des&lt;br /&gt;
expecco-Prozesses.  Ausgaben gehen in das expecco-Log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warnung]] &#039;&#039;&#039;Telnet ist ein veraltetes&lt;br /&gt;
Protokoll ohne Verschlüsselung.&#039;&#039;&#039; Passwörter werden im Klartext&lt;br /&gt;
über die Leitung übertragen; jeder im Netzpfad kann sie lesen.&lt;br /&gt;
Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative&lt;br /&gt;
bietet (typisch: alte Industriesteuerungen, Laborgeräte,&lt;br /&gt;
eingebettete Messgeräte ohne SSH-Stack).  Für alles andere&lt;br /&gt;
[[#SSH und SFTP]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Das expecco-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (interne Demo)&lt;br /&gt;
&lt;br /&gt;
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler&lt;br /&gt;
8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für&lt;br /&gt;
Terminal-Optionen.  Verbindungsaufbau zum Ziel-Host:Port; nach&lt;br /&gt;
optionalem In-Band-Login können beide Seiten Daten senden.&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY, Agent-Weiterleitung, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks.&lt;br /&gt;
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack als HTTPS-Transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Netz]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31742</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31742"/>
		<updated>2026-08-21T18:18:58Z</updated>

		<summary type="html">&lt;p&gt;Sv: add native SSH/SFTP action blocks (26.2) to &amp;#039;From expecco actions&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on OpenSSL or libssh.  Use this for anything that touches credentials or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine. Used for local-tool integration and for the local end of a remote workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No encryption, passwords on the wire in clear.  Use only when the target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
&amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt; subclass that lets the rest of ST/X treat a remote SFTP path the same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user[:password]@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.  The optional &amp;lt;code&amp;gt;:password&amp;lt;/code&amp;gt; piece is the&lt;br /&gt;
RFC-3986-style userinfo password &amp;amp;mdash; see&lt;br /&gt;
[[#Password authentication]] for when this is appropriate and what&lt;br /&gt;
the security trade-offs are.  When present, it is used as a USERAUTH&lt;br /&gt;
fallback after the normal publickey/agent attempts and is &#039;&#039;&#039;never&#039;&#039;&#039;&lt;br /&gt;
re-emitted by the printable URL form, so logging the filename does&lt;br /&gt;
not leak the credential.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Refresh&#039;&#039;&#039; button in the toolbar (the round-arrow icon&lt;br /&gt;
between &#039;&#039;Forward&#039;&#039; and &#039;&#039;DirectoryUp&#039;&#039;) re-reads both the&lt;br /&gt;
directory tree and the contents pane on demand.  Works uniformly&lt;br /&gt;
for local and SFTP paths; for SFTP it also flushes the per-file&lt;br /&gt;
STAT cache, so changes made directly on the remote side become&lt;br /&gt;
visible immediately rather than waiting for the 5-second cache TTL&lt;br /&gt;
to expire.&lt;br /&gt;
&lt;br /&gt;
The small arrow next to the Refresh icon opens a dropdown with a&lt;br /&gt;
single checkbox, &#039;&#039;&#039;Automatic Refresh&#039;&#039;&#039;, controlling the&lt;br /&gt;
background polling task that walks every expanded tree item to&lt;br /&gt;
detect external changes.  The default depends on the current root:&lt;br /&gt;
&lt;br /&gt;
* Local filesystem &amp;amp;rarr; &#039;&#039;&#039;on&#039;&#039;&#039; (10-second cycle, matches the long-standing behaviour).&lt;br /&gt;
* SFTP &amp;amp;rarr; &#039;&#039;&#039;off&#039;&#039;&#039;.  Each cycle costs one STAT round-trip per child, which is fine for a handful of local directories but painful over the network.  Click Refresh manually when you need to pick up remote changes.&lt;br /&gt;
&lt;br /&gt;
When you navigate between local and SFTP roots the toggle flips&lt;br /&gt;
automatically &amp;amp;mdash; but only if you haven&#039;t overridden it for&lt;br /&gt;
the previous root.  An explicit user choice is preserved across&lt;br /&gt;
navigations.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of the filesystem holding the currently displayed directory.  Works uniformly for local paths and SFTP paths; for SFTP it requires the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; extension (every modern OpenSSH does).  Sizes are reported in IEC binary units (MiB, GiB, TiB) — the largest unit yielding a value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039; rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From the Launcher ==&lt;br /&gt;
&lt;br /&gt;
The Launcher&#039;s &#039;&#039;&#039;Workspace&#039;&#039;&#039; submenu carries two stand-alone&lt;br /&gt;
entries (gated on the SSH package being loaded):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH Terminal&#039;&#039;&#039; &amp;amp;mdash; prompts for a target in the form &amp;lt;code&amp;gt;user[:password]@host[:port]&amp;lt;/code&amp;gt; and opens a top-level VT100 terminal connected to it.  No FileBrowser involved &amp;amp;mdash; this is the launcher analogue of the FileBrowserV2 &#039;&#039;&#039;Tools &amp;amp;rarr; SSH Connect...&#039;&#039;&#039; entry.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connection&#039;&#039;&#039; &amp;amp;mdash; prompts for an SFTP target (same URL grammar as the FileBrowserV2 location bar, see [[#From the FileBrowserV2]]) and opens a fresh FileBrowserV2 already navigated to that path.&lt;br /&gt;
&lt;br /&gt;
Both entries honour the URL-embedded password syntax described in&lt;br /&gt;
[[#Password authentication]].&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
Since expecco 26.2 the plugin additionally provides &#039;&#039;&#039;native&#039;&#039;&#039; SSH and SFTP action blocks, implemented in pure Smalltalk on top of &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt; — no external &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; binary is required.  A connection is opened once and its &amp;lt;code&amp;gt;SshHandle&amp;lt;/code&amp;gt; is passed to the following blocks.&lt;br /&gt;
&lt;br /&gt;
SSH blocks:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH - Open Connection&#039;&#039;&#039; — connect and authenticate (explicit private key, ssh-agent, or the default &amp;lt;code&amp;gt;~/.ssh&amp;lt;/code&amp;gt; keys), yielding an &amp;lt;code&amp;gt;SshHandle&amp;lt;/code&amp;gt; for the blocks below.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Open Connection with Password&#039;&#039;&#039; — the same, but authenticating with a plaintext password instead of a key.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Execute Command&#039;&#039;&#039; — run a single command; captures stdout, stderr and exit status, with an optional stdin stream piped to the remote process.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Execute Commands&#039;&#039;&#039; — run a list of commands, each as its own exec channel, on an open connection.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Execute Commands In Shell&#039;&#039;&#039; — run a list of commands in one persistent login shell, so that state such as the working directory carries across commands.&lt;br /&gt;
* &#039;&#039;&#039;SSH - Close Connection&#039;&#039;&#039; — close a connection opened above.&lt;br /&gt;
&lt;br /&gt;
SFTP blocks (each layered on an open &amp;lt;code&amp;gt;SshHandle&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP - Upload File&#039;&#039;&#039; and &#039;&#039;&#039;SFTP - Upload File from String/Stream&#039;&#039;&#039; — write a local file, or in-memory content / a read stream, to a remote path (streamed, without buffering the whole file).&lt;br /&gt;
* &#039;&#039;&#039;SFTP - Download File&#039;&#039;&#039; — read a remote file to a local file and/or into a supplied write stream (streamed, without buffering the whole file).&lt;br /&gt;
* &#039;&#039;&#039;SFTP - List Directory&#039;&#039;&#039; — list the entries of a remote directory.&lt;br /&gt;
* &#039;&#039;&#039;SFTP - Delete File&#039;&#039;&#039;, &#039;&#039;&#039;SFTP - Rename&#039;&#039;&#039; and &#039;&#039;&#039;SFTP - Make Directory&#039;&#039;&#039; — remote file management.&lt;br /&gt;
&lt;br /&gt;
Each of these blocks ships with a runnable Test/Demo network (its &#039;&#039;Test/Demo&#039;&#039; tab) that connects to the host given by the &amp;lt;code&amp;gt;DEMO_SSH_HOST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DEMO_SSH_PORT&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DEMO_SSH_USER&amp;lt;/code&amp;gt; environment variables.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
&amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only; gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file unencrypted (agent-only mode ignores the passphrase, since the OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to &#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally; a ST/X on the Windows side does not.  Bridging needs a helper like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Password authentication ==&lt;br /&gt;
&lt;br /&gt;
Public-key (with or without ssh-agent) is the recommended path.&lt;br /&gt;
Password authentication is supported as a fallback for the cases&lt;br /&gt;
where keys are not available: legacy hosts, on-the-fly access to a&lt;br /&gt;
test box, scripted access to an account whose owner refuses to add&lt;br /&gt;
your public key.  Keep in mind:&lt;br /&gt;
&lt;br /&gt;
* The plaintext password lives in memory on the ST/X side for the lifetime of the &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; &amp;amp;mdash; treat it like any other in-memory secret.&lt;br /&gt;
* The server still controls which methods it accepts.  If &amp;lt;code&amp;gt;sshd_config&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;PasswordAuthentication no&amp;lt;/code&amp;gt;, no Smalltalk-side configuration can override that.&lt;br /&gt;
* Wire-level the handshake is RFC 4252 §8: the password is sent inside the encrypted SSH transport, never in clear over the network.&lt;br /&gt;
&lt;br /&gt;
=== From a URL ===&lt;br /&gt;
&lt;br /&gt;
Both the FileBrowserV2 location bar and the launcher&#039;s&lt;br /&gt;
&#039;&#039;&#039;Workspace &amp;amp;rarr; SFTP Connection&#039;&#039;&#039; / &#039;&#039;&#039;Workspace &amp;amp;rarr; SSH&lt;br /&gt;
Terminal&#039;&#039;&#039; prompts accept an inline password in the standard&lt;br /&gt;
RFC-3986 userinfo position:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://alice:s3cret@host.example.com/srv/data&lt;br /&gt;
ssh   alice:s3cret@host.example.com:2222&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The parser splits on the &#039;&#039;&#039;last&#039;&#039;&#039; &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; so passwords&lt;br /&gt;
containing &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; still parse; the first &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt;&lt;br /&gt;
inside the userinfo separates user from password.  Passwords&lt;br /&gt;
containing &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; are not supported in this form &amp;amp;mdash;&lt;br /&gt;
use the programmatic API below.&lt;br /&gt;
&lt;br /&gt;
The password is stripped from the printable URL: every place that&lt;br /&gt;
ends up logging or displaying the filename (status line,&lt;br /&gt;
&amp;lt;code&amp;gt;printOn:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nameString&amp;lt;/code&amp;gt;, the breadcrumb path)&lt;br /&gt;
shows the credential-free form&lt;br /&gt;
&amp;lt;code&amp;gt;sftp://alice@host.example.com/...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From code ===&lt;br /&gt;
&lt;br /&gt;
Two equivalent ways to attach a password to an&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;/ literal -- simplest, password is just an ivar&lt;br /&gt;
client := SSH::Client newToHost:&#039;host.example.com&#039; port:22 user:&#039;alice&#039;.&lt;br /&gt;
client password:&#039;s3cret&#039;.&lt;br /&gt;
client connect.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;/ callback -- lazy; the password never lives on the client.&lt;br /&gt;
&amp;quot;/ Useful with an interactive prompt, a keychain lookup, or a&lt;br /&gt;
&amp;quot;/ vault-fetched secret that you do not want long-lived in memory.&lt;br /&gt;
client passwordCallback:[ Dialog requestPassword:&#039;SSH password&#039; ].&lt;br /&gt;
client connect.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The callback wins if both are set.  Both are evaluated lazily&lt;br /&gt;
during &amp;lt;code&amp;gt;#connect&amp;lt;/code&amp;gt;, after publickey/agent attempts have&lt;br /&gt;
been rejected, so a working key always wins over a password when&lt;br /&gt;
both are configured.&lt;br /&gt;
&lt;br /&gt;
=== Authentication order ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;amp;gt;&amp;amp;gt;authenticate&amp;lt;/code&amp;gt; walks every available&lt;br /&gt;
credential in this order, returning on the first one the server&lt;br /&gt;
accepts:&lt;br /&gt;
&lt;br /&gt;
# ssh-agent identities, if &amp;lt;code&amp;gt;#useAgent&amp;lt;/code&amp;gt; was called and the agent has loaded keys.&lt;br /&gt;
# ed25519 private-key seed, if &amp;lt;code&amp;gt;#privateKeyFromFile:&amp;lt;/code&amp;gt; picked one up.&lt;br /&gt;
# RSA private key.&lt;br /&gt;
# ECDSA private key.&lt;br /&gt;
# Password, if &amp;lt;code&amp;gt;#password:&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;#passwordCallback:&amp;lt;/code&amp;gt; was set &#039;&#039;&#039;and&#039;&#039;&#039; the server still advertises &amp;lt;code&amp;gt;password&amp;lt;/code&amp;gt; in its USERAUTH_FAILURE methods list.&lt;br /&gt;
&lt;br /&gt;
Each step is skipped when the server&#039;s last&lt;br /&gt;
&amp;lt;code&amp;gt;USERAUTH_FAILURE&amp;lt;/code&amp;gt; reply dropped the relevant method&lt;br /&gt;
from its allowed list &amp;amp;mdash; we do not bang on&lt;br /&gt;
&amp;lt;code&amp;gt;publickey&amp;lt;/code&amp;gt; after the server stops offering it.  The&lt;br /&gt;
password attempt is only fired when the server still wants&lt;br /&gt;
&amp;lt;code&amp;gt;password&amp;lt;/code&amp;gt;, so a misconfigured client password against a&lt;br /&gt;
key-only server raises a clean&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::AuthenticationError&amp;lt;/code&amp;gt; without an extra useless&lt;br /&gt;
round-trip.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s walkback plus each waiter&#039;s, formatted as plain text.  Use when a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed (e.g. legacy PEM, encrypted-without-agent) — the file is skipped, others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime), no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
[[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every modern OpenSSH does), overwrite is atomic; on the rare server that does not, the receiver is emulated as delete-then-rename and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost three round-trips per directory icon, which made the original tree expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link. Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
&#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer to disk on an open handle.  Available on the low-level&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe, EOF, MNU on nil socket) evicts the dead pool entry, opens a fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP + one SFTP channel per host means N concurrent requests serialise.  Pipelining over multiple SshClients in the pool (preferred), or a transport-level reader process demultiplexing to per-channel inboxes, would let the tree pane keep listing while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (first batch only) + CLOSE — three RTTs per probe; needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style canonicalisation.  (Atomic-overwrite rename is already handled via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension; see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31741</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31741"/>
		<updated>2026-08-21T12:10:26Z</updated>

		<summary type="html">&lt;p&gt;Sv: 26.2: the four SNMP entries consolidated into one&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
* Feature: [[ElementaryBlock_Element/en#Scheme_Blocks_(Bridged)|bridged Scheme]] (currently only Racket Scheme) action blocks&lt;br /&gt;
* Feature: [[ElementaryBlock_Element/en#Octave_Blocks_(Bridged)|bridged Octave/Matlab]] action blocks&lt;br /&gt;
* Feature: [[Expecco_API/en#C#_Actions|bridged C#]] action blocks&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; AI Coding provider &amp;quot;&#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039;&amp;quot; — uses your existing Claude subscription via the locally installed &#039;&#039;Claude Code&#039;&#039; command line program instead of an API key, so no key has to be entered and no per-token API charges are billed. Choose it like any other provider in the settings dialog (Plugins → AI Coding); the API key, endpoint URL and proxy fields are hidden for it because they do not apply, and the authentication method reads &amp;quot;Subscription (external login)&amp;quot;. It requires &#039;&#039;Claude Code&#039;&#039; to be installed and logged in once (run &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in a terminal and complete the login). The model is selectable either as a tier alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — always the current model of that tier) or as a pinned model id.&lt;br /&gt;
* Feature: two new AI actions that work on the selected &#039;&#039;&#039;class&#039;&#039;&#039; rather than on a single method, reachable from the &#039;&#039;&#039;AI&#039;&#039;&#039; menu of the class browser: &amp;quot;&#039;&#039;&#039;Explain Class&#039;&#039;&#039;&amp;quot; explains the class as a whole — what it is responsible for, what its instance variables hold and how its protocols fit together — and &amp;quot;&#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039;&amp;quot; proposes a class documentation text which the &amp;quot;[Apply]&amp;quot; button installs into the class&#039; documentation.&lt;br /&gt;
* Feature: HTTP/2 (h2) support in the embedded web server, negotiated via TLS ALPN, with HPACK header compression and request multiplexing over a single connection. Implemented in pure Smalltalk, so no external library is required. This is the server side only — the HTTP client (&#039;&#039;HTTPInterface&#039;&#039;) continues to speak HTTP/1.1. A server configured without a certificate stays on HTTP/1.1, because h2 is negotiated during the TLS handshake; the offer can be turned off with &amp;lt;code&amp;gt;HTTPServer http2Enabled:false&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Feature: ALM repository project version access in the project tree; see versions directly in a second tree (readonly), drag items out of it, execute test plans etc. Create new version and easy commit.&lt;br /&gt;
* Feature: TEAM support; multiple teams users can live-edit the same suite for merge, group development, passing work to other users or demonstration. &lt;br /&gt;
* Feature: improved SSDP service announcement&lt;br /&gt;
* Feature: full ipV6 UDP support (mostly socketAddress fixes and multicast support)&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[SNMP Plugin Reference/en|SNMP]] support, reimplemented in expecco itself - no &#039;&#039;net-snmp&#039;&#039; installation is needed any more, and the blocks behave identically on every supported platform. SNMP v1, v2c and v3 (authentication with MD5, SHA-1 or one of the SHA-2 protocols of RFC 7860, encryption with DES or AES-128); a whole table read by one block with its rows and their INDEX decoded (ifTable, ipAddrTable, tcpConnTable, ...); many devices asked the same question at once, in parallel; traps and informs both received and sent. An up to date set of MIB modules (net-snmp 5.9.5.2) is delivered, so the names of SNMPv2-MIB, IF-MIB, IP-MIB, TCP-MIB and friends resolve out of the box - the deprecated RFC1213-MIB groups (&#039;&#039;at&#039;&#039;, &#039;&#039;egp&#039;&#039;, &#039;&#039;ipRouteTable&#039;&#039;) are not part of it and are shown numerically, add &#039;&#039;RFC1213-MIB.txt&#039;&#039; to a MIB directory (&amp;quot;Add MIB Directory&amp;quot;) if a device still needs those names. Fixes on the way: object identifiers were corrupted on 64bit systems, which made most SNMP blocks return wrong values.&lt;br /&gt;
* Fix: JSON printer&#039;s recursive store detection was generating false positives&lt;br /&gt;
* Improvement: better Python syntax highlighter&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039;, &#039;&#039;&#039;ollama&#039;&#039;&#039; and others as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via [[Tools_FileBrowser/en|FileBrowser]])&lt;br /&gt;
* Feature: public/private keypair generation via a [[Tools_FileBrowser/en|FileBrowser]] menu (for easy SSH setup)&lt;br /&gt;
* Improvement: Bundled python3 installer updated to version 3.13.14&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed the [[Number_API_Functions|Number]] stack (see also in [[Numeric_Limits/en| Numeric Limits]]):&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. and type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan). Now all test cases produce a result within the precision limits of their type&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]&lt;br /&gt;
* UI: &#039;&#039;&#039;Ctrl-Return&#039;&#039;&#039; now accepts the default action in every modal dialog — both the modern SimpleDialog-based ones (check-in log message, search dialogs, ...) and old-style DialogBox-based ones (EnterBox, OptionBox, InfoBox, ...). Unlike plain Return, Ctrl-Return submits the dialog even when the focus is on a multi-line text editor (which normally keeps Return as a newline), so there is no need to tab off the editor first.&lt;br /&gt;
* UI: Transcript (the console) always appends text at end.&lt;br /&gt;
* UI: Transcript does not scroll to end on incoming text while moving the scrollbar &lt;br /&gt;
* Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
* Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
* Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Performance: speedup of cryptographic algorithms (affects key generation and other)&lt;br /&gt;
* Performance: tuned loading of stored ets/elf files (30-40% speedup)&lt;br /&gt;
* Performance: further speedup when loading test-result archives that embed large execution logs — typical load is roughly a third faster again&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31740</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31740"/>
		<updated>2026-08-21T12:05:47Z</updated>

		<summary type="html">&lt;p&gt;Sv: 26.2 SNMP: link to the plugin page, SHA-2, tables and traps&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
* Feature: [[ElementaryBlock_Element/en#Scheme_Blocks_(Bridged)|bridged Scheme]] (currently only Racket Scheme) action blocks&lt;br /&gt;
* Feature: [[ElementaryBlock_Element/en#Octave_Blocks_(Bridged)|bridged Octave/Matlab]] action blocks&lt;br /&gt;
* Feature: [[Expecco_API/en#C#_Actions|bridged C#]] action blocks&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; AI Coding provider &amp;quot;&#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039;&amp;quot; — uses your existing Claude subscription via the locally installed &#039;&#039;Claude Code&#039;&#039; command line program instead of an API key, so no key has to be entered and no per-token API charges are billed. Choose it like any other provider in the settings dialog (Plugins → AI Coding); the API key, endpoint URL and proxy fields are hidden for it because they do not apply, and the authentication method reads &amp;quot;Subscription (external login)&amp;quot;. It requires &#039;&#039;Claude Code&#039;&#039; to be installed and logged in once (run &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in a terminal and complete the login). The model is selectable either as a tier alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — always the current model of that tier) or as a pinned model id.&lt;br /&gt;
* Feature: two new AI actions that work on the selected &#039;&#039;&#039;class&#039;&#039;&#039; rather than on a single method, reachable from the &#039;&#039;&#039;AI&#039;&#039;&#039; menu of the class browser: &amp;quot;&#039;&#039;&#039;Explain Class&#039;&#039;&#039;&amp;quot; explains the class as a whole — what it is responsible for, what its instance variables hold and how its protocols fit together — and &amp;quot;&#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039;&amp;quot; proposes a class documentation text which the &amp;quot;[Apply]&amp;quot; button installs into the class&#039; documentation.&lt;br /&gt;
* Feature: HTTP/2 (h2) support in the embedded web server, negotiated via TLS ALPN, with HPACK header compression and request multiplexing over a single connection. Implemented in pure Smalltalk, so no external library is required. This is the server side only — the HTTP client (&#039;&#039;HTTPInterface&#039;&#039;) continues to speak HTTP/1.1. A server configured without a certificate stays on HTTP/1.1, because h2 is negotiated during the TLS handshake; the offer can be turned off with &amp;lt;code&amp;gt;HTTPServer http2Enabled:false&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Feature: ALM repository project version access in the project tree; see versions directly in a second tree (readonly), drag items out of it, execute test plans etc. Create new version and easy commit.&lt;br /&gt;
* Feature: TEAM support; multiple teams users can live-edit the same suite for merge, group development, passing work to other users or demonstration. &lt;br /&gt;
* Feature: improved SSDP service announcement&lt;br /&gt;
* Feature: full ipV6 UDP support (mostly socketAddress fixes and multicast support)&lt;br /&gt;
* Feature: new [[SNMP Plugin Reference/en|SNMP]] blocks: read a whole table (ifTable, ipAddrTable, tcpConnTable, ...) with its rows and their INDEX decoded, ask many devices the same question at once, and receive traps and informs with a trap listener as well as send them.&lt;br /&gt;
* Improvement: the [[SNMP Plugin Reference/en|&#039;&#039;&#039;SNMP&#039;&#039;&#039;]] blocks no longer use the external &#039;&#039;net-snmp&#039;&#039; library; SNMP v1, v2c and v3 (authentication with MD5, SHA-1 or one of the SHA-2 protocols of RFC 7860, encryption with DES or AES-128) are now implemented in expecco itself and behave identically on all supported platforms.&lt;br /&gt;
* Improvement: an up to date set of MIB modules (from net-snmp 5.9.5.2) is delivered with the SNMP library, so symbolic names such as those of IF-MIB, IP-MIB or TCP-MIB are resolved out of the box. The deprecated RFC1213-MIB groups (&#039;&#039;at&#039;&#039;, &#039;&#039;egp&#039;&#039; and &#039;&#039;ipRouteTable&#039;&#039;) are no longer part of it and are shown numerically instead; add &#039;&#039;RFC1213-MIB.txt&#039;&#039; to a MIB directory (&amp;quot;Add MIB Directory&amp;quot;) if a device still requires those names.&lt;br /&gt;
* Fix: SNMP object identifiers were corrupted on 64bit systems, so that most SNMP blocks returned wrong values.&lt;br /&gt;
* Fix: JSON printer&#039;s recursive store detection was generating false positives&lt;br /&gt;
* Improvement: better Python syntax highlighter&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039;, &#039;&#039;&#039;ollama&#039;&#039;&#039; and others as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via [[Tools_FileBrowser/en|FileBrowser]])&lt;br /&gt;
* Feature: public/private keypair generation via a [[Tools_FileBrowser/en|FileBrowser]] menu (for easy SSH setup)&lt;br /&gt;
* Improvement: Bundled python3 installer updated to version 3.13.14&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed the [[Number_API_Functions|Number]] stack (see also in [[Numeric_Limits/en| Numeric Limits]]):&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. and type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan). Now all test cases produce a result within the precision limits of their type&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]&lt;br /&gt;
* UI: &#039;&#039;&#039;Ctrl-Return&#039;&#039;&#039; now accepts the default action in every modal dialog — both the modern SimpleDialog-based ones (check-in log message, search dialogs, ...) and old-style DialogBox-based ones (EnterBox, OptionBox, InfoBox, ...). Unlike plain Return, Ctrl-Return submits the dialog even when the focus is on a multi-line text editor (which normally keeps Return as a newline), so there is no need to tab off the editor first.&lt;br /&gt;
* UI: Transcript (the console) always appends text at end.&lt;br /&gt;
* UI: Transcript does not scroll to end on incoming text while moving the scrollbar &lt;br /&gt;
* Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
* Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
* Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Performance: speedup of cryptographic algorithms (affects key generation and other)&lt;br /&gt;
* Performance: tuned loading of stored ets/elf files (30-40% speedup)&lt;br /&gt;
* Performance: further speedup when loading test-result archives that embed large execution logs — typical load is roughly a third faster again&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Weitere_Plugins&amp;diff=31739</id>
		<title>Weitere Plugins</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Weitere_Plugins&amp;diff=31739"/>
		<updated>2026-08-21T12:05:46Z</updated>

		<summary type="html">&lt;p&gt;Sv: SNMP Plugin ergaenzt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* [[Code Ausführung]]&lt;br /&gt;
* [[Daten/Nachrichten/Dokument Formate]]&lt;br /&gt;
* [[QM Schnittstellen]]&lt;br /&gt;
* [[Import/Export von Spezifikationen]]&lt;br /&gt;
* [[Databases|Datenbanken]]&lt;br /&gt;
&amp;lt;!-- * [[API]] --&amp;gt;&lt;br /&gt;
* [[NoSQL|NoSQL Datenbanken]]&lt;br /&gt;
* [[GembirdPowerControlPlugin Reference]] -- kontrolliert eine fernsteuerbare Stromversorgung zum autom. An- bzw. Abschalten von Geräten (Teil des Basissystems)&lt;br /&gt;
* [[SNMP Plugin Reference/en|SNMP Plugin]] -- fragt SNMP-fähige Geräte ab (Router, Switches, Drucker, Server, USVs), liest ganze Tabellen und empfängt bzw. sendet Traps (Teil des Basissystems)&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=SNMP_Plugin_Reference/en&amp;diff=31738</id>
		<title>SNMP Plugin Reference/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=SNMP_Plugin_Reference/en&amp;diff=31738"/>
		<updated>2026-08-21T12:01:07Z</updated>

		<summary type="html">&lt;p&gt;Sv: SNMP plugin description: library blocks, protocol versions, MIBs, tables, traps, Test/Demo variables&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== SNMP Plugin ==&lt;br /&gt;
The SNMP plugin lets a test suite talk to SNMP capable equipment - routers, switches, printers, servers,&lt;br /&gt;
UPS units, sensors - and receive the notifications such a device sends. It delivers the &#039;&#039;&#039;SNMP Library&#039;&#039;&#039;,&lt;br /&gt;
whose blocks cover the manager side of SNMP v1, v2c and v3: reading and writing objects, walking subtrees,&lt;br /&gt;
reading whole tables, resolving MIB names, and receiving as well as sending traps.&lt;br /&gt;
&lt;br /&gt;
Everything is implemented in expecco itself. No &#039;&#039;net-snmp&#039;&#039; installation and no other external library is&lt;br /&gt;
needed, and the blocks behave the same on every supported platform.&lt;br /&gt;
&lt;br /&gt;
=== The SNMP Library ===&lt;br /&gt;
The blocks are found in the library &amp;quot;&#039;&#039;SNMP Library&#039;&#039;&amp;quot;, grouped into six categories. Every block carries its&lt;br /&gt;
own documentation, every pin explains what it expects, and every block has a Test/Demo network which shows it&lt;br /&gt;
in use.&lt;br /&gt;
&lt;br /&gt;
==== SNMP Connection ====&lt;br /&gt;
* &#039;&#039;&#039;Open SNMP Session&#039;&#039;&#039; - open a session to a device with SNMP v1 or v2c, using a community string.&lt;br /&gt;
* &#039;&#039;&#039;Open SNMPV3 Session&#039;&#039;&#039; - open an SNMPv3 session with a user name, an authentication and an encryption protocol, and the two passphrases. The context name and context engine id can be given for agents which partition their MIB into contexts.&lt;br /&gt;
* &#039;&#039;&#039;Close SNMP Session&#039;&#039;&#039; - release the session and its socket.&lt;br /&gt;
* &#039;&#039;&#039;SNMP Timeout/Retries&#039;&#039;&#039; - how long to wait for an answer and how often to repeat a request.&lt;br /&gt;
* &#039;&#039;&#039;SNMP Session Info&#039;&#039;&#039; - which host, port, version, community and context a session handle refers to.&lt;br /&gt;
* &#039;&#039;&#039;SNMP Last Error&#039;&#039;&#039; - why the last request did not deliver a value, as a symbolic reason (noResponse, timedOut, noSuchName, wrongDigest, notWritable, ...).&lt;br /&gt;
* &#039;&#039;&#039;SNMP Max Repetitions&#039;&#039;&#039; - how many objects one GetBulk request asks for; this is what a walk uses.&lt;br /&gt;
&lt;br /&gt;
==== SNMP Requests ====&lt;br /&gt;
* &#039;&#039;&#039;SNMP Get&#039;&#039;&#039; / &#039;&#039;&#039;SNMP Get Next&#039;&#039;&#039; / &#039;&#039;&#039;SNMP Get Bulk&#039;&#039;&#039; - read one object, the object following it, or a batch of following objects.&lt;br /&gt;
* &#039;&#039;&#039;SNMP Get Subtree&#039;&#039;&#039; - walk everything below an object (for instance the whole &#039;&#039;system&#039;&#039; group or an entire table) and answer it as an oid to value dictionary.&lt;br /&gt;
* &#039;&#039;&#039;SNMP Set&#039;&#039;&#039; - write one object. Without an explicit type the type is taken from the MIB definition, and the object is read back afterwards, so the outputs show what the agent really stored.&lt;br /&gt;
* &#039;&#039;&#039;SNMP Multi Get&#039;&#039;&#039; / &#039;&#039;&#039;Multi Get Next&#039;&#039;&#039; / &#039;&#039;&#039;Multi Get Bulk&#039;&#039;&#039; / &#039;&#039;&#039;Multi Set&#039;&#039;&#039; - the same for several objects in ONE request, which is much faster than asking one by one.&lt;br /&gt;
* &#039;&#039;&#039;SNMP Get with Default&#039;&#039;&#039; - read an object which only some devices implement, answering a default instead of failing.&lt;br /&gt;
* &#039;&#039;&#039;Read SNMP Table&#039;&#039;&#039; - read a whole conceptual table (ifTable, ipAddrTable, tcpConnTable, ...) and answer its rows in index order. The rows are also delivered one by one, so a following step can run once per row.&lt;br /&gt;
* &#039;&#039;&#039;Table Row Value&#039;&#039;&#039; / &#039;&#039;&#039;Table Row Index&#039;&#039;&#039; / &#039;&#039;&#039;Table Row as Dictionary&#039;&#039;&#039; - read a column of a row by name or number, the decoded INDEX of a row, or the whole row as a columnName to value dictionary.&lt;br /&gt;
* &#039;&#039;&#039;SNMP Get on Hosts&#039;&#039;&#039; / &#039;&#039;&#039;SNMP Multi Get on Hosts&#039;&#039;&#039; - ask many devices the same question at once. The hosts are queried in parallel, so the block takes about as long as the slowest device rather than the sum of all of them; a host which does not answer is reported, not an error.&lt;br /&gt;
&lt;br /&gt;
==== MIB Access ====&lt;br /&gt;
* &#039;&#039;&#039;Name to OID&#039;&#039;&#039; / &#039;&#039;&#039;OID to Name&#039;&#039;&#039; - translate between a MIB name (&#039;&#039;sysDescr.0&#039;&#039;, &#039;&#039;SNMPv2-MIB::sysDescr.0&#039;&#039;) and the numeric object identifier.&lt;br /&gt;
* &#039;&#039;&#039;Resolve OIDs in Dictionary Keys&#039;&#039;&#039; / &#039;&#039;&#039;... Values&#039;&#039;&#039; - replace the OIDs in the result of a walk or a multi get by their MIB names, which is what makes such a result readable in the report.&lt;br /&gt;
* &#039;&#039;&#039;Describe MIB Object&#039;&#039;&#039; - what the MIB knows about an object: full name, syntax, access, status, unit, the labels of an enumerated INTEGER, and whether it is a table or a table row with its INDEX.&lt;br /&gt;
&lt;br /&gt;
==== MIB Management ====&lt;br /&gt;
* &#039;&#039;&#039;Add MIB Directory&#039;&#039;&#039; - parse the MIB files of a directory and add them, so vendor specific names can be used in the other blocks.&lt;br /&gt;
* &#039;&#039;&#039;Shutdown MIB&#039;&#039;&#039; - forget everything read from MIB files; the next name to resolve reads them again.&lt;br /&gt;
&lt;br /&gt;
==== SNMP Traps ====&lt;br /&gt;
* &#039;&#039;&#039;Start Trap Listener&#039;&#039;&#039; - listen for notifications on a UDP port. The standard port 162 needs root privileges on unix, so an unprivileged port such as 11162 is often used.&lt;br /&gt;
* &#039;&#039;&#039;Wait for Trap&#039;&#039;&#039; - wait for the next notification and answer its sender, version, identifier (resolved through the MIB) and all its variables. Notifications which arrived before the block ran are not lost, and an inform request is acknowledged automatically.&lt;br /&gt;
* &#039;&#039;&#039;Stop Trap Listener&#039;&#039;&#039; - stop listening and release the port.&lt;br /&gt;
* &#039;&#039;&#039;Send Trap&#039;&#039;&#039; - send a notification to a trap receiver, as a plain trap or as an inform request which the receiver has to acknowledge.&lt;br /&gt;
&lt;br /&gt;
=== Protocol versions and security ===&lt;br /&gt;
SNMP &#039;&#039;&#039;v1&#039;&#039;&#039; and &#039;&#039;&#039;v2c&#039;&#039;&#039; identify the caller with a community string, which travels in clear text.&lt;br /&gt;
&lt;br /&gt;
SNMP &#039;&#039;&#039;v3&#039;&#039;&#039; authenticates and encrypts with the User-based Security Model. Supported protocols:&lt;br /&gt;
* authentication: &#039;&#039;md5&#039;&#039; and &#039;&#039;sha1&#039;&#039; (RFC 3414), and the SHA-2 protocols &#039;&#039;sha224&#039;&#039;, &#039;&#039;sha256&#039;&#039;, &#039;&#039;sha384&#039;&#039; and &#039;&#039;sha512&#039;&#039; (RFC 7860). Current net-snmp builds refuse MD5, so prefer SHA-256.&lt;br /&gt;
* encryption: &#039;&#039;des&#039;&#039; and &#039;&#039;aes128&#039;&#039; (RFC 3826). Encryption is only possible together with authentication.&lt;br /&gt;
&lt;br /&gt;
Engine discovery and the clock synchronisation an authenticated session needs happen automatically.&lt;br /&gt;
&lt;br /&gt;
=== MIBs ===&lt;br /&gt;
A current set of MIB modules is delivered with the library, so the usual names - those of SNMPv2-MIB, IF-MIB,&lt;br /&gt;
IP-MIB, TCP-MIB, UDP-MIB, HOST-RESOURCES-MIB and many more - resolve without any setup. Vendor MIBs are added&lt;br /&gt;
with &amp;quot;&#039;&#039;Add MIB Directory&#039;&#039;&amp;quot;, either from a directory of your own or from &#039;&#039;~/.snmp/mibs&#039;&#039;, which is read&lt;br /&gt;
automatically.&lt;br /&gt;
&lt;br /&gt;
The deprecated RFC1213-MIB groups &#039;&#039;at&#039;&#039;, &#039;&#039;egp&#039;&#039; and &#039;&#039;ipRouteTable&#039;&#039; are not part of the delivered set;&lt;br /&gt;
objects below them are shown numerically. Their replacements are &#039;&#039;ipNetToMediaTable&#039;&#039;, &#039;&#039;ipCidrRouteTable&#039;&#039;&lt;br /&gt;
and &#039;&#039;inetCidrRouteTable&#039;&#039;. If a device really needs the old names, drop &#039;&#039;RFC1213-MIB.txt&#039;&#039; into a MIB&lt;br /&gt;
directory.&lt;br /&gt;
&lt;br /&gt;
=== Reading a table ===&lt;br /&gt;
&amp;quot;&#039;&#039;Read SNMP Table&#039;&#039;&amp;quot; answers the rows of a conceptual table. A row knows its columns by name and the INDEX&lt;br /&gt;
which identifies it, and &amp;quot;&#039;&#039;Table Row Index&#039;&#039;&amp;quot; decodes that INDEX as the MIB defines it - the interface number&lt;br /&gt;
for &#039;&#039;ifTable&#039;&#039;, the IP address for &#039;&#039;ipAddrTable&#039;&#039;, the four parts of a connection for &#039;&#039;tcpConnTable&#039;&#039;.&lt;br /&gt;
Values arrive as Smalltalk objects: a counter as a number, an &#039;&#039;ifOperStatus&#039;&#039; as its label (&#039;&#039;up&#039;&#039;, &#039;&#039;down&#039;&#039;),&lt;br /&gt;
an IP address as an address, &#039;&#039;sysUpTime&#039;&#039; as a time duration.&lt;br /&gt;
&lt;br /&gt;
=== Traps and informs ===&lt;br /&gt;
A test can wait for a notification instead of polling: start a listener, let the device do whatever should&lt;br /&gt;
trigger the trap, and read it with &amp;quot;&#039;&#039;Wait for Trap&#039;&#039;&amp;quot;. Traps of all three versions are accepted; for SNMPv3&lt;br /&gt;
the sender is the authoritative engine, so the listener localizes the keys per sending device by itself.&lt;br /&gt;
Notifications which do not authenticate, or whose community is not accepted, are dropped silently.&lt;br /&gt;
&lt;br /&gt;
An inform request is acknowledged automatically, and &amp;quot;&#039;&#039;Send Trap&#039;&#039;&amp;quot; can send one, so a suite can also play&lt;br /&gt;
the role of the device.&lt;br /&gt;
&lt;br /&gt;
=== Test/Demo networks ===&lt;br /&gt;
Every block has a Test/Demo network. The ones which need a device use these environment variables of the&lt;br /&gt;
library, so that one place decides which equipment the demos talk to:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variable !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| DemoSNMPHost || the device the demos read from&lt;br /&gt;
|-&lt;br /&gt;
| DemoSNMPCommunity || the community string used for v1 / v2c&lt;br /&gt;
|-&lt;br /&gt;
| DemoSNMPV3User || the SNMPv3 user name&lt;br /&gt;
|-&lt;br /&gt;
| DemoSNMPV3AuthPassphrase || its authentication passphrase (the demo agent uses SHA-256)&lt;br /&gt;
|-&lt;br /&gt;
| DemoSNMPV3PrivPassphrase || its encryption passphrase (the demo agent uses AES-128)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Change them to a device of your own before running the demos. The trap demos need nothing on the network -&lt;br /&gt;
they start a listener, send themselves a trap and read it back.&lt;br /&gt;
&lt;br /&gt;
=== See also ===&lt;br /&gt;
* [https://www.rfc-editor.org/rfc/rfc3416 RFC 3416] - the SNMP protocol operations&lt;br /&gt;
* [https://www.rfc-editor.org/rfc/rfc3414 RFC 3414] - the User-based Security Model of SNMPv3&lt;br /&gt;
* [https://www.rfc-editor.org/rfc/rfc7860 RFC 7860] - the SHA-2 authentication protocols&lt;br /&gt;
* [https://www.rfc-editor.org/rfc/rfc2578 RFC 2578] - SMIv2, how a MIB module is written&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31733</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31733"/>
		<updated>2026-08-16T14:38:25Z</updated>

		<summary type="html">&lt;p&gt;Sv: 26.2: SNMP without net-snmp, current MIBs, 64bit OID fix&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
* Feature: [[ElementaryBlock_Element/en#Scheme_Blocks_(Bridged)|bridged Scheme]] (currently only Racket Scheme) action blocks&lt;br /&gt;
* Feature: [[ElementaryBlock_Element/en#Octave_Blocks_(Bridged)|bridged Octave/Matlab]] action blocks&lt;br /&gt;
* Feature: [[Expecco_API/en#C#_Actions|bridged C#]] action blocks&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; AI Coding provider &amp;quot;&#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039;&amp;quot; — uses your existing Claude subscription via the locally installed &#039;&#039;Claude Code&#039;&#039; command line program instead of an API key, so no key has to be entered and no per-token API charges are billed. Choose it like any other provider in the settings dialog (Plugins → AI Coding); the API key, endpoint URL and proxy fields are hidden for it because they do not apply, and the authentication method reads &amp;quot;Subscription (external login)&amp;quot;. It requires &#039;&#039;Claude Code&#039;&#039; to be installed and logged in once (run &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in a terminal and complete the login). The model is selectable either as a tier alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — always the current model of that tier) or as a pinned model id.&lt;br /&gt;
* Feature: two new AI actions that work on the selected &#039;&#039;&#039;class&#039;&#039;&#039; rather than on a single method, reachable from the &#039;&#039;&#039;AI&#039;&#039;&#039; menu of the class browser: &amp;quot;&#039;&#039;&#039;Explain Class&#039;&#039;&#039;&amp;quot; explains the class as a whole — what it is responsible for, what its instance variables hold and how its protocols fit together — and &amp;quot;&#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039;&amp;quot; proposes a class documentation text which the &amp;quot;[Apply]&amp;quot; button installs into the class&#039; documentation.&lt;br /&gt;
* Feature: HTTP/2 (h2) support in the embedded web server, negotiated via TLS ALPN, with HPACK header compression and request multiplexing over a single connection. Implemented in pure Smalltalk, so no external library is required. This is the server side only — the HTTP client (&#039;&#039;HTTPInterface&#039;&#039;) continues to speak HTTP/1.1. A server configured without a certificate stays on HTTP/1.1, because h2 is negotiated during the TLS handshake; the offer can be turned off with &amp;lt;code&amp;gt;HTTPServer http2Enabled:false&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Feature: ALM repository project version access in the project tree; see versions directly in a second tree (readonly), drag items out of it, execute test plans etc. Create new version and easy commit.&lt;br /&gt;
* Feature: TEAM support; multiple teams users can live-edit the same suite for merge, group development, passing work to other users or demonstration. &lt;br /&gt;
* Feature: improved SSDP service announcement&lt;br /&gt;
* Feature: full ipV6 UDP support (mostly socketAddress fixes and multicast support)&lt;br /&gt;
* Improvement: the &#039;&#039;&#039;SNMP&#039;&#039;&#039; blocks no longer use the external &#039;&#039;net-snmp&#039;&#039; library; SNMP v1, v2c and v3 (authentication with MD5 or SHA-1, encryption with DES or AES-128) are now implemented in expecco itself and behave identically on all supported platforms.&lt;br /&gt;
* Improvement: an up to date set of MIB modules (from net-snmp 5.9.5.2) is delivered with the SNMP library, so symbolic names such as those of IF-MIB, IP-MIB or TCP-MIB are resolved out of the box. The deprecated RFC1213-MIB groups (&#039;&#039;at&#039;&#039;, &#039;&#039;egp&#039;&#039; and &#039;&#039;ipRouteTable&#039;&#039;) are no longer part of it and are shown numerically instead; add &#039;&#039;RFC1213-MIB.txt&#039;&#039; to a MIB directory (&amp;quot;Add MIB Directory&amp;quot;) if a device still requires those names.&lt;br /&gt;
* Fix: SNMP object identifiers were corrupted on 64bit systems, so that most SNMP blocks returned wrong values.&lt;br /&gt;
* Fix: JSON printer&#039;s recursive store detection was generating false positives&lt;br /&gt;
* Improvement: better Python syntax highlighter&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039;, &#039;&#039;&#039;ollama&#039;&#039;&#039; and others as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via [[Tools_FileBrowser/en|FileBrowser]])&lt;br /&gt;
* Feature: public/private keypair generation via a [[Tools_FileBrowser/en|FileBrowser]] menu (for easy SSH setup)&lt;br /&gt;
* Improvement: Bundled python3 installer updated to version 3.13.14&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed the [[Number_API_Functions|Number]] stack (see also in [[Numeric_Limits/en| Numeric Limits]]):&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. and type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan). Now all test cases produce a result within the precision limits of their type&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]&lt;br /&gt;
* UI: &#039;&#039;&#039;Ctrl-Return&#039;&#039;&#039; now accepts the default action in every modal dialog — both the modern SimpleDialog-based ones (check-in log message, search dialogs, ...) and old-style DialogBox-based ones (EnterBox, OptionBox, InfoBox, ...). Unlike plain Return, Ctrl-Return submits the dialog even when the focus is on a multi-line text editor (which normally keeps Return as a newline), so there is no need to tab off the editor first.&lt;br /&gt;
* UI: Transcript (the console) always appends text at end.&lt;br /&gt;
* UI: Transcript does not scroll to end on incoming text while moving the scrollbar &lt;br /&gt;
* Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
* Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
* Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Performance: speedup of cryptographic algorithms (affects key generation and other)&lt;br /&gt;
* Performance: tuned loading of stored ets/elf files (30-40% speedup)&lt;br /&gt;
* Performance: further speedup when loading test-result archives that embed large execution logs — typical load is roughly a third faster again&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31673</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31673"/>
		<updated>2026-08-06T08:36:52Z</updated>

		<summary type="html">&lt;p&gt;Sv: Cgs Korrekturen in Individuelle Toolrechte wiederhergestellt (von mir versehentlich ueberschrieben)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|KI Coding Plugin|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Die hier beschriebenen KI-Funktionen sind Teil des Lizenz-Features &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  Ist dieses Feature in Ihrer Lizenz nicht enthalten, erscheinen die &#039;&#039;Ask AI&#039;&#039;-Menüeinträge zwar weiterhin sichtbar in den Editor-Toolbars, sind aber deaktiviert (Tooltip: &amp;quot;&#039;&#039;Install the AI coding plugin to enable&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic (aka Claude)&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI (i.e. ChatGPT)&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
* &#039;&#039;&#039;llama.cpp&#039;&#039;&#039; lokal oder remote&lt;br /&gt;
* &#039;&#039;&#039;Groq&#039;&#039;&#039;, &#039;&#039;&#039;Zen&#039;&#039;&#039;, &#039;&#039;&#039;LLaMa&#039;&#039;&#039;, &#039;&#039;&#039;Tabnine&#039;&#039;&#039; etc.&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; — nutzt Ihr vorhandenes Claude-Abonnement statt eines API-Schlüssels &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Inhouse&#039;&#039;&#039; — ihre eigene in-house (in-Firma) KI.&lt;br /&gt;
&lt;br /&gt;
Wichtig:&amp;lt;br&amp;gt;&lt;br /&gt;
Der zusätzliche Eintrag &#039;&#039;&#039;Inhouse&#039;&#039;&#039; ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern oder einer anderen fimeninternen KI chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Lizenzierung ==&lt;br /&gt;
&lt;br /&gt;
Die KI-Funktionen sind auf &#039;&#039;&#039;zwei getrennte Lizenz-Features&#039;&#039;&#039; aufgeteilt. Die Trennung verläuft genau entlang der Grenze zwischen &#039;&#039;lesen&#039;&#039; und &#039;&#039;verändern&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;KI Coding&#039;&#039;&#039; (im Lizenzfile: &#039;&#039;AI Coding&#039;&#039;) — die Grundlizenz. Sie lädt das Plugin überhaupt erst und schaltet Chat-Fenster, Anbieterauswahl und die lesenden (&#039;&#039;safe&#039;&#039;) Werkzeuge frei.&lt;br /&gt;
* &#039;&#039;&#039;KI Advanced Coding&#039;&#039;&#039; (im Lizenzfile: &#039;&#039;AI Advanced Coding&#039;&#039;) — ein eigenes, zusätzlich zu erwerbendes Feature. Es setzt &#039;&#039;KI Coding&#039;&#039; voraus und schaltet die schreibenden (&#039;&#039;unsafe&#039;&#039;) Werkzeuge frei.&lt;br /&gt;
&lt;br /&gt;
=== KI Coding ===&lt;br /&gt;
&lt;br /&gt;
Ohne dieses Feature ist das Plugin nicht geladen: die &#039;&#039;Ask AI&#039;&#039;-Einträge bleiben in den Editor-Toolbars sichtbar, sind aber deaktiviert (Tooltip: &amp;quot;&#039;&#039;Install the AI coding plugin to enable&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;KI Coding&#039;&#039; können Sie in vollem Umfang mit dem Modell arbeiten, solange es dabei bleibt, Ihr Projekt zu &#039;&#039;lesen&#039;&#039;: Elemente suchen, Netzwerke und Quellcode analysieren, Aktivitylogs auswerten, Dokumentation entwerfen, Fehlerursachen erklären lassen. Vorschläge des Modells — etwa neuer Quellcode für eine Elementaraktion — erscheinen im Chat-Fenster und werden von Ihnen bewusst übernommen (&#039;&#039;Apply&#039;&#039;-Knopf oder copy/paste). Die Entscheidung, ob eine Änderung in die Suite gelangt, liegt in jedem Einzelfall bei Ihnen.&lt;br /&gt;
&lt;br /&gt;
=== KI Advanced Coding ===&lt;br /&gt;
&lt;br /&gt;
Dieses Feature schaltet die Werkzeuge frei, mit denen das Modell Ihr Projekt und Ihre Arbeitsumgebung &#039;&#039;&#039;selbst verändern&#039;&#039;&#039; kann — im Wesentlichen die im Abschnitt [[#Unsafe Tools|Unsafe Tools]] aufgeführten Funktionen: Elemente anlegen, Netzwerke ändern, Methoden und Klassen definieren, Aktionen und Testfälle ausführen sowie Änderungen in die Versionsverwaltung einchecken.&lt;br /&gt;
&lt;br /&gt;
Fehlt das Feature, stehen diese Werkzeuge &#039;&#039;&#039;auch dann nicht zur Verfügung, wenn sie im ChatView ausdrücklich erlaubt wurden&#039;&#039;&#039;. Das Modell erhält in diesem Fall eine Fehlermeldung statt der Ausführung; die Sitzung läuft normal weiter.&lt;br /&gt;
&lt;br /&gt;
=== Sicherheitsaspekte ===&lt;br /&gt;
&lt;br /&gt;
Die Lizenz ist die &#039;&#039;&#039;äußere&#039;&#039;&#039; von zwei voneinander unabhängigen Schutzschichten. Beide müssen eine Aktion erlauben, damit sie ausgeführt wird:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lizenz-Ebene&#039;&#039;&#039; (&#039;&#039;KI Advanced Coding&#039;&#039;) — organisatorisch, gilt für die gesamte Installation und ist &#039;&#039;&#039;vom Anwender nicht umschaltbar&#039;&#039;&#039;. Sie hängt an der signierten Lizenzdatei und lässt sich nicht über eine Einstellung, eine Umgebungsvariable oder eine Konfigurationsdatei aktivieren.&lt;br /&gt;
* &#039;&#039;&#039;Laufzeit-Ebene&#039;&#039;&#039; (&#039;&#039;MCP&#039;&#039;-Knopf, Tools-Menü, Planungsmodus) — situativ, gilt für die einzelne Chat-Sitzung und ist vom Anwender jederzeit umschaltbar. Siehe [[#Individuelle Toolrechte|Individuelle Toolrechte]].&lt;br /&gt;
&lt;br /&gt;
Daraus ergeben sich die praktisch wichtigen Eigenschaften:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Eine Organisation kann verbindlich festlegen, dass die KI grundsätzlich nur lesend arbeitet.&#039;&#039;&#039; Wird &#039;&#039;KI Advanced Coding&#039;&#039; nicht lizenziert, bleibt es dabei — unabhängig davon, was einzelne Anwender in ihrem ChatView einstellen, und unabhängig davon, ob jemand versehentlich &amp;quot;Alle Tools automatisch erlauben&amp;quot; aktiviert.&lt;br /&gt;
* &#039;&#039;&#039;Grundsatz der geringsten Rechte.&#039;&#039;&#039; Der Auslieferungszustand ist lesend; Schreibrechte müssen bewusst erworben werden und sind damit auch eine dokumentierte Entscheidung, kein Nebeneffekt einer Voreinstellung.&lt;br /&gt;
* &#039;&#039;&#039;Die Prüfung gilt auch für den Zugriff von außen.&#039;&#039;&#039; Greift ein externes CLI-Programm (&#039;&#039;claude code&#039;&#039;, &#039;&#039;cursor&#039;&#039;, &#039;&#039;zed&#039;&#039;, &#039;&#039;tabnine&#039;&#039;) über das MCP-Protokoll auf expecco zu, unterliegen die schreibenden Werkzeuge derselben Prüfung. Ein externes Programm kann sie nicht umgehen — es erhält dieselbe Fehlermeldung wie das Modell im internen Chat.&lt;br /&gt;
* &#039;&#039;&#039;Der Prüfpunkt liegt bei der Ausführung, nicht in der Oberfläche.&#039;&#039;&#039; Die Werkzeuge werden nicht lediglich im Menü ausgeblendet; der Aufruf selbst wird abgewiesen. Ein ausgeblendeter Menüeintrag wäre keine Sicherheitsmaßnahme.&lt;br /&gt;
&lt;br /&gt;
Ebenso wichtig ist, was die Lizenz &#039;&#039;&#039;nicht&#039;&#039;&#039; leistet:&lt;br /&gt;
&lt;br /&gt;
* Sie begrenzt, &#039;&#039;&#039;was die KI in expecco tun darf&#039;&#039;&#039; — nicht, &#039;&#039;&#039;welche Daten das Haus verlassen&#039;&#039;&#039;. Welcher Anbieter Ihren Quellcode zu sehen bekommt, entscheidet allein die Anbieterwahl; siehe [[#Datenschutz / Datenfluss|Datenschutz / Datenfluss]]. Auch mit reinem &#039;&#039;KI Coding&#039;&#039; wird beim Einsatz eines Cloud-Anbieters Projektinhalt übertragen.&lt;br /&gt;
* Sie ersetzt nicht die Prüfung dessen, was das Modell vorschlägt. Auch eine lizenzierte Änderung ist eine Änderung eines Modells und gehört wie jeder fremde Beitrag reviewt.&lt;br /&gt;
* Sie schützt nicht vor einem kompromittierten CLI-Programm auf demselben Rechner. Für sicherheitskritische Umgebungen gelten weiterhin die Hinweise im Abschnitt [[#Tool Use|Tool Use]] zur Isolation solcher Rechner.&lt;br /&gt;
&lt;br /&gt;
Für eine sicherheitskritische Umgebung ergibt sich daraus die restriktivste sinnvolle Konfiguration: &#039;&#039;KI Coding&#039;&#039; ohne &#039;&#039;KI Advanced Coding&#039;&#039;, kombiniert mit einem lokal betriebenen Modell (&#039;&#039;ollama&#039;&#039; oder &#039;&#039;llama.cpp&#039;&#039;). Dann verlässt kein Projektinhalt Ihr Netz, und die KI kann ausschließlich lesen und vorschlagen.&lt;br /&gt;
&lt;br /&gt;
== Architektur und Sicherheit ==&lt;br /&gt;
&lt;br /&gt;
Mit &amp;quot;&#039;&#039;Sicherheit&#039;&#039;&amp;quot; ist hier gemeint: &amp;quot;&#039;&#039;können die Daten den Rechner oder ihre Abteilung/Firma verlassen&#039;&#039; bzw. &#039;&#039;kann die KI Schaden anrichten indem sie auf Ihrem Rechner unkontrolliert Code ausführt oder Daten manipuliert&#039;&#039;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Wenn hohe Sicherheit gefordert ist (sensible Daten, Algorithmen, Workflows) muss Ihr Netzadmin durch geeignete Maßnahmen (Firewall, Router/Switch Konfiguration etc.) verhindern, dass Zugriffe sowohl ausgehend als auch eingehend zu/von außerhalb ihrer Domäne möglich sind. &lt;br /&gt;
Das &amp;quot;unsichtbar machen&amp;quot; entsprechender Einstellungsdialoge in expecco wäre hierzu nicht dienlich, da bei offenen Ports unzählige andere Möglichkeiten bestehen (curl, webbrowser, low-level Socket API etc.).&lt;br /&gt;
&lt;br /&gt;
Zur Sicherheit ihrer eigenen Testsuite und möglichen Aktionen der KI lesen Sie bitte die unten aufgeführten Abschnitte zu [[#tool_use|&amp;quot;Tool Use&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
=== Architektur ===&lt;br /&gt;
&lt;br /&gt;
Im folgenden werden die Einstellungen und die zugehörigen Datenflüsse/kanäle beschrieben.&lt;br /&gt;
&lt;br /&gt;
Mögliche Setups sind:&lt;br /&gt;
&lt;br /&gt;
==== KI Firmenintern ====&lt;br /&gt;
* direkte Verbindung zu einer KI auf einem Rechner in ihrem lokalen Netzwerk, Firmennetz oder einem definiert sicheren Firmenanbieter.&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Hoch&#039;&#039;&#039; &amp;lt;small&amp;gt;(weder Daten noch Chat-Text gehen aus dem Haus)&amp;lt;/small&amp;gt;&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:InhouseSetup1.png|Einstellung&lt;br /&gt;
Datei:ArchInhouseSetup1.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:expecco kommuniziert ausschließlich und direkt zu dieser URL; keine Applikation dazwischen. Insbesondere kein &amp;quot;&amp;lt;code&amp;gt;claude.exe&amp;lt;/code&amp;gt;&amp;quot; oder ein anderes Command Line Interface (CLI) Programm. Ihre Eingaben im expecco Chat Fenster gehen direkt (verpackt als JSON) an die konfigurierte Adresse und deren Antwort erscheint (entpackt aus JSON) im expecco Chat Fenster. Nachrichten werden ausschließlich mit dem von Ihnen konfigurierten Host ausgetauscht.&lt;br /&gt;
&lt;br /&gt;
::- wählen Sie dazu &amp;quot;inhouse&amp;quot; und geben hostname+port+URL zu diesem host ein; typischerweise haben diese die Form &amp;quot;&amp;lt;code&amp;gt;firmenAI:11434/v1/chat/completions&amp;lt;/code&amp;gt;&amp;quot; oder auch 80 oder 8080 als port. Fragen Sie ihren Netzwerkadmin im Zweifel, auch ob ein API Key (= Zugangsschlüssel) erforderlich ist.&lt;br /&gt;
&lt;br /&gt;
==== KI auf Ihrem eigenen Rechner ====&lt;br /&gt;
&lt;br /&gt;
* direkte Verbindung zu einer lokalen KI auf ihrem eignen persönlichen Rechner&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Sehr Hoch&#039;&#039;&#039; (weder Daten noch Chat verlassen ihren Rechner)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:LocalSetup2.png|Einstellung&lt;br /&gt;
Datei:ArchLocalSetup2.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:auch hier kommuniziert expecco ausschließlich und direkt zu diesem ihrem lokalen Rechner, auf der Sie selbst ein Modell installiert und am Laufen haben (ollama oder llama.cpp). Ob dies im einzelnen sinnvoll ist hängt von der Leistungsfähigkeit ihres eigenen Rechners ab (empfohlen wird eine oder mehrere leistungsfähige GPUs mit viel VRAM (&amp;gt;=32Gb), großer RAM Speicherausbau (&amp;gt;=64Gb) und ein leistungsfähiges Modell (mindestens 30B, besser 120B mit großem Kontext,da reichen aber 32GB VRAM nicht); eigene Erfahrungen haben wir unten in diesem Dokument zusammengetragen).&lt;br /&gt;
::- wählen Sie dazu &amp;quot;ollama&amp;quot; oder &amp;quot;llama.cpp&amp;quot; und geben als hostname &amp;quot;localhost&amp;quot; ein. Falls sie einen dedizierten Rechner in der Abteilung haben, kann natürlich auch dessen Hostname eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
==== KI von einem Cloudanbieter ====&lt;br /&gt;
* direkte Verbindung zu einem externen Anbieter (wie Anthropic, OpenAI etc.).&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Fragwürdig&#039;&#039;&#039; (Sie müssen dem Anbieter und IP Verbindung vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup4.png|Einstellung&lt;br /&gt;
Datei:ArchExternalSetup3.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Die Interaktion erfolgt lediglich mit der von Ihnen eingestellten URL über das expecco-interne chat Fenster. In sicherheitskritischem Umfeld ist jedoch davon abzuraten und ihre Netzadministrator wird diesen Zugang vermutlich auch nicht zulassen da (je nach URL) ihre Daten und ihr Chatverlauf an externe Rechner gehen, oder von fremden Geheimdiensten mitgelesen werden könnten). Prinzipiell sollte dies dem Netzadmin aber bekannt sein, und auf Netzwerkebene gesperrt sein, da ein solcher Zugriff auch anderen Programmen verwehrt werden muss (curl, Webbrowser etc.). Insofern ist ratsam, solche Verbindungen auf administrativer Ebene (Firewall, Router/Switch Konfiguration etc.) zu verhindern. Natürlich gilt diees nicht, falls sie eine eigenen firmeninterne cloud Infrastruktur besitzen, die vertrauenswürdig ist.&lt;br /&gt;
::- wählen Sie dazu &amp;quot;Anthropic, OpenAI, ...&amp;quot; und geben hostname+port+URL zu diesem host ein (wobei die Vorgabe im Eingabefeld typischerweise schon passt); typischerweise brauchen die Anbieter einen Zugangsschlüssel (sog. API key), den Sie bei der Registrierung vom Anbieter oder von ihrem Netzadmin erhalten. Achtung: verschiedene Anbieter (u.a. Anthropic) erlauben hier nur die Abrechnung über Ihr Token Budget, nicht über einen Pro/Max oder Enterprise plan. Es kann also hier zu erhöhten Kosten führen. Es ist uns weder technisch noch juristisch möglich, dies zu verhindern.&lt;br /&gt;
&lt;br /&gt;
==== KI über CLI (eg. claude code); Bedienung über CLI  ====&lt;br /&gt;
* indirekte Verbindung via CLI (z.B. ClaudeCode, Kiro, Tabnine, OpenCode, LMStudio etc.).&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Unsicher&#039;&#039;&#039; (Sie müssen sowohl Anbieter und dem Modell vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup4.png|Einstellung&lt;br /&gt;
Datei:ArchExternalSetup1.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Hier baut ein CLI Programm (z.B. &amp;quot;claude.exe&amp;quot;) die Verbindung zum KI Modell auf (was natürlich seinerseits wiederum eine lokale in-house KI sein könnte). Dieses CLI Programm verbindet sich dann mit expecco und hat dort beschränkten Zugriff auf ihre Testsuite (über mcp). Die Interaktion erfolgt mit dem CLI Programm, die Bedienung des Modells erfolgt im CLI Programm. Das CLI hat kontrollieren Zugriff auf expecco über das sog. MCP Protokoll. Es ist zu beachten, dass die Konfiguration dem CLI Zugriff auf Dateien ermöglicht und es auch andere Aktionen auf Ihrem Rechner ausführen kann (shell/batch/powershell, Dateizugriffe etc.). Das Modell kann über das CLI Programm auch auf Ressourcen außerhalb expecco zugreifen. Und es könnte das System bzw. ihr Netz geziehlt ausspionieren oder manipulieren ohne daß expecco dies bemerkt oder verhindert. Sie müssen also sowohl dem Anbieter, der IP Verbindung als auch dem CLI Programm vertrauen.&lt;br /&gt;
::- sie müssen dem lokalen CLI Programm den Zugriff auf expecco erlauben. gehen Sie dazu in das &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Web-Dienste&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;MCP Zugriff erlauben (AI Coding)&#039;&#039;&amp;quot;.&amp;lt;br&amp;gt;Die Konfiguration zum eigentlichen Modell erfolgt im CLI Programm Ihrer Wahl und ist nicht unter der Kontrolle von expecco; expecco erlaubt damit lediglich  die Kontrolle von außerhalb über das MCP Protokoll. Eine Einstellung des Anbieters ist nicht notwendig; sie wird nicht benutzt, können daher beliebige Angaben machen.&lt;br /&gt;
&lt;br /&gt;
==== KI über transparente CLI (nur claude code); Bedienung über ChatView  ====&lt;br /&gt;
* indirekte Verbindung via unsichtbarer ClaudeCode CLI.&lt;br /&gt;
Sicherheit: &#039;&#039;&#039;Unsicher&#039;&#039;&#039; (Anbieter und Modell vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup5.png|Einstellung&lt;br /&gt;
Datei:ArchExternalCLIStdioSetup5.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Auch hier erfolgt die Verbindung über das ClaudeCode CLI Programm, welches jedoch ohne Benutzeroberfläche den Verkehr lediglich weiter leitet (via stdin/stdout). Die Benutzerinteraktion erfolgt über das expecco-interne chat Fenster, der tatsächliche Modellzugriff vom CLI. Auch hier muss die Konfiguration des Modellzugriffs im CLI Programm erfolgen. Auch hier ist nicht technisch ausgeschlossen, daß das CLI Programm auf Daten außerhalb expecco zugreift. Falls das vom CLI technisch ermöglicht wird, könnte das Modell solche Zugriffe auslösen. Auch hier muß Modell, Verbindung und CLI Programm vertraut werden.&lt;br /&gt;
&lt;br /&gt;
=== Tool Use ===&lt;br /&gt;
&lt;br /&gt;
Der eigentlichen Mehrwert der KI besteht in der Möglichkeit dem Modell Zugriff auf das im expecco gezeigte Testprojekt zu gestatten. Es kann die Elemente des Baums lesen, Netzwerke analysieren und Ergebnisse (AktivityLogs) lesen.&lt;br /&gt;
&lt;br /&gt;
Dazu sendet das Modell sog. &amp;quot;Tool Calls&amp;quot; zurück, die vom Empfänger im JSON Datenstrom erkannt und ausgeführt werden. Diese werden im folgenden &amp;quot;Tool Calls&amp;quot; genannt.&lt;br /&gt;
&lt;br /&gt;
Ist ein CLI Programm (claude.exe, openCode.exe etc.) der Partner des Modells, erfolgt diese Erkennung dort, und die tools werden anhand des Toolnamens entweder im CLI selbst ausgeführt (Dateien lesen der schreiben, shell/batch scripts ausführen, etc.) oder über das sog. MCP Protokoll an Drittprogramme weiter geleitet.&lt;br /&gt;
In unserem Fall stellt expecco die unten beschriebenen MCP tools bereit. Neben diesen könnten aber auch andere Aktionen (geheim oder offen) vom CLI ausgeführt werden. Und sie können dem CLI auch andere MCP Zugänge zu anderen Programmen bereitstellen. Sie müssen in diesem Fall also unbedingt dem CLI Programm und dem Modell und der IP Verbindung zur Außenwelt vertrauen. Sollten sie im sicherheitskritischen Umfeld solch ein Setup wählen ist unbedingt geraten, diesen Rechner vom Rest ihres Netzwerks zu isolieren, keine sensiblen Daten auf diesem Rechner zu halten, und den Verkehr zur Außenwelt über einen separaten Kanal abzuwickeln.&lt;br /&gt;
&lt;br /&gt;
Ist kein CLI Programm involviert (i.e. die Verbindung geht von expecco direkt zum Modell) erfolgt die Erkennung von tool calls innerhalb expecco, und es ist dem Modell nicht möglich, andere Aktionen als die unten aufgeführten Funktionen aufzurufen. Sie haben also volle Kontrolle darüber.&lt;br /&gt;
&lt;br /&gt;
==== Tool Funktionen von expecco ====&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen dienen dazu, dem Modell lesend und/oder schreibend auf ihre Testsuite (das im Browser dargestellte Projekt) zuzugreifen. Wie bereits beschrieben sind dies auch Funktionen die über MCP einem CLI Programm zur Verfügung gestellt werden, falls ein CLI Programm involviert ist.&lt;br /&gt;
&lt;br /&gt;
Die expecco tool Funktionen wurden von uns eingeteilt in sog. &amp;quot;Safe&amp;quot; und &amp;quot;Unsafe&amp;quot; tools.&amp;lt;br&amp;gt;Als sicher gelten rein lesende, als unsafe solche welche ihre Suite manipulieren oder Aktionen ausführen können.&lt;br /&gt;
&lt;br /&gt;
Sie können in den expecco Einstellungen festlegen, ob tools generell verboten werden, nur safe tools erlaubt werden, oder auch für jedes individuelle tool eine Erlaubnis gegeben wird. Außerdem können Sie bestimmen ob bei jedem individuellen call eine Nachfrage um Erlaubnis erfolgen soll.&lt;br /&gt;
&lt;br /&gt;
===== Safe Tools =====&lt;br /&gt;
* Suche von Elementen im Projekt&lt;br /&gt;
* Lesen der Schritte, Verbindungen, Pins, etc. in einem Netzwerk&lt;br /&gt;
* Lesen des Quellcodes einer Elementaraktion&lt;br /&gt;
* Lesen des Aktivitylogs nach einer Ausführung&lt;br /&gt;
* Suchen und Lesen von Hilfsfunktionen im unterliegenden Framework (eg. Smalltalk Basisklassen)&lt;br /&gt;
&lt;br /&gt;
===== Unsafe Tools =====&lt;br /&gt;
* Anlegen neuer Elemente&lt;br /&gt;
* Änderungen in einem Netzwerk (Schritten, Verbindungen etc.)&lt;br /&gt;
* Ausführen einer Aktion, eines Testfalls oder Testplans&lt;br /&gt;
&lt;br /&gt;
==== Im ChatView ====&lt;br /&gt;
&lt;br /&gt;
===== Tool Calls Generell verbieten/erlauben =====&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;mcp&amp;quot; Button im  Chatview bestimmt ob tool calls prinzipiell erlaubt oder verboten werden.&amp;lt;br&amp;gt;Fall generell erlaubt werden die unten beschriebenen Einzeleinstellungen wirksam;&amp;lt;br&amp;gt;falls generell verboten sind diese irrelevant.&amp;lt;br&amp;gt;&lt;br /&gt;
Ohne tool calls können Sie immer noch  mit dem Modell interagieren und sich von diesem z.B. Vorschläge zu Quellcode geben lassen - Sie müssen diese dann aber von Hand aus dem Chatview übernehmen oder mit copy/paste in ihre Suite eintragen. Falls sie unsafe tools erlaubt haben, könnte das Modell so eine Änderung automatisch durchführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ChatViewMCP1.png|Enable/Disable Tools&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Individuelle Toolrechte =====&lt;br /&gt;
Falls tools nicht generell verboten sind (&amp;quot;MCP erlaubt&amp;quot;), können die Rechte gruppenweise und/oder individuell eingestellt werden. Dazu dient das &amp;quot;Tools&amp;quot; Menu des ChatViews:&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ChatViewMCP2.png|Enable/Disable Individual Tools&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Menu umfasst die Einträge:&lt;br /&gt;
* &amp;quot;MCP Tools verwenden&amp;quot;&lt;br /&gt;
:die selbe Funktion wie der &amp;quot;MCP&amp;quot; Toolbar Knopf &lt;br /&gt;
* &amp;quot;Alle Tools automatisch erlauben&amp;quot;&lt;br /&gt;
:unterdrückt die individuelle Erlaubnis Nachfrage; Achtung: der Titel dieser Menufunktion ist aktuell missverständlich (und wird in der nächsten Release geändert); es betrifft die Nachfrage der prinzipiell schon durch die Einstellungen erlaubten tools.&lt;br /&gt;
* &amp;quot;Planungsmodus&amp;quot;&lt;br /&gt;
:alle tool calls werden automatisch abgelehnt; damit kann man vorab testen, welche Aktionen das Modell durchführen würde&lt;br /&gt;
* &amp;quot;Tools Schnellmenu&amp;quot;&lt;br /&gt;
:wie im Bild gezeigt: gruppenweise safe/unsafe tools erlauben, gruppenweise Domäne (Expecco / Smalltalk Framework), individuell Rechte einstellen&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;. &lt;br /&gt;
Es gibt keinen eXept-seitigen Proxy oder Zwischenspeicher.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, dass die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind. Die Verbindung zu den KI-Providern wird aber immer über eine SSL/TLS 1.3 verschlüsselte Verbindung hergestellt (von expecco-Seite aus wird auch Post-Quanten-Kryptographie unterstützt).&lt;br /&gt;
&lt;br /&gt;
Post-Quanten-Kryptographie wirkt allerdings nur, wenn &#039;&#039;&#039;beide&#039;&#039;&#039; Seiten sie beherrschen. expecco bietet die hybride Gruppe &#039;&#039;X25519MLKEM768&#039;&#039; (X25519 kombiniert mit ML-KEM-768, RFC 9697) an erster Stelle an; ob sie zum Einsatz kommt, entscheidet der Anbieter. Nachgemessen im August 2026 — es handelt sich um tatsächlich beobachtete Handshakes, nicht um Herstellerangaben — handeln diese voreingestellten Anbieter die Gruppe aus:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic&#039;&#039;&#039; (&#039;&#039;api.anthropic.com&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI&#039;&#039;&#039; (&#039;&#039;api.openai.com&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;Groq&#039;&#039;&#039; und &#039;&#039;&#039;Zen&#039;&#039;&#039; (&#039;&#039;api.groq.com&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;Mistral&#039;&#039;&#039; (&#039;&#039;api.mistral.ai&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;OpenRouter&#039;&#039;&#039; (&#039;&#039;openrouter.ai&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
Bei lokal betriebenen Modellen (&#039;&#039;ollama&#039;&#039;, &#039;&#039;llama.cpp&#039;&#039;) stellt sich die Frage nicht: die Verbindung läuft über die Loopback-Schnittstelle und verlässt den Rechner nicht. Bei den Zugängen &#039;&#039;&#039;Inhouse&#039;&#039;&#039; und &#039;&#039;&#039;Tabnine&#039;&#039;&#039; hängt es an Ihrem eigenen Server — dort können Sie es selbst prüfen, etwa mit &amp;lt;code&amp;gt;openssl s_client -connect &#039;&#039;host&#039;&#039;:443 -groups X25519MLKEM768&amp;lt;/code&amp;gt;; scheitert der Handshake, unterstützt der Server die Gruppe nicht.&lt;br /&gt;
&lt;br /&gt;
Der praktische Nutzen liegt beim Angriffsmodell &amp;quot;&#039;&#039;harvest now, decrypt later&#039;&#039;&amp;quot;: aufgezeichneter Verkehr lässt sich auch später, mit einem hinreichend leistungsfähigen Quantenrechner, nicht nachträglich entschlüsseln. Das ist genau dann relevant, wenn Quellcode Ihrer Testsuiten über die Leitung geht. &#039;&#039;&#039;Am Grundproblem ändert es nichts&#039;&#039;&#039;: der Anbieter selbst sieht den Inhalt im Klartext — dagegen hilft nur die Anbieterwahl.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Chat Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es zwei Aktionen, die sich auf die ausgewählte &#039;&#039;&#039;Klasse&#039;&#039;&#039;&lt;br /&gt;
beziehen statt auf eine einzelne Methode &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
Es genügt, die Klasse auszuwählen; eine Methodenauswahl ist dafür nicht nötig:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Explain Class&#039;&#039;&#039; — erklärt die Klasse als Ganzes: wofür sie zuständig ist, welche Rolle ihre Instanzvariablen spielen, wie ihre Protokolle zusammenwirken und worauf man beim Verwenden achten muss.&lt;br /&gt;
* &#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039; — schlägt einen Dokumentationstext für die Klasse vor; &#039;&#039;&#039;[Apply]&#039;&#039;&#039; trägt diesen in die Dokumentation der Klasse ein.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren nur mit vision-fähigen Modellen (bei OpenAI z.B. gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic, OpenAI etc.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039; — dieser Anbieter verwendet nicht die API, sondern das lokal installierte Kommandozeilenprogramm &#039;&#039;Claude Code&#039;&#039; und damit Ihr vorhandenes Claude-Abonnement.  Es wird kein API-Schlüssel benötigt, und es fallen keine tokenbasierten API-Kosten an.  Die Felder &#039;&#039;&#039;API Key&#039;&#039;&#039;, &#039;&#039;&#039;API URL&#039;&#039;&#039; und &#039;&#039;&#039;Proxy&#039;&#039;&#039; werden für diesen Anbieter ausgeblendet, da sie hier keine Bedeutung haben; als Authentifizierung erscheint &amp;quot;Subscription (external login)&amp;quot;.  Voraussetzung ist, dass &#039;&#039;Claude Code&#039;&#039; installiert ist und einmalig angemeldet wurde — dazu &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in einer Konsole starten und die Anmeldung abschließen.  Das Modell kann als Stufen-Alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — jeweils das aktuelle Modell dieser Stufe) oder als fester Modellname angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
* Ollama/llama.cpp: kein API Key erforderlich&lt;br /&gt;
* Inhouse: fragen Sie ihren Admin&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten (CLI Programm) ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
: Anm.: Dieser Abschnitt beschreibt den umgekehrten Weg — ein extern laufendes &#039;&#039;Claude Code&#039;&#039; greift auf expecco zu.  Wenn Sie &#039;&#039;Claude Code&#039;&#039; umgekehrt als KI-Anbieter &#039;&#039;innerhalb&#039;&#039; von expecco nutzen möchten, siehe den Anbieter &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; im Abschnitt [[#Einstellungen (AI Coding)|Einstellungen]] &#039;&#039;(ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls typischerweise im Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen.&amp;lt;br&amp;gt;Mit &amp;quot;/mcps&amp;quot; sollte diese aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Dieser Abschnitt ist veraltet; die unten aufgeführten Aufgaben könnnen&lt;br /&gt;
nun 1:1 auch so im Chatfenster ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen  weg - es sei denn sie dienen der Entscheidung. Tatsächlich erhöhen sie lediglich den Tokenverbrauch.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (ollama) ==&lt;br /&gt;
&lt;br /&gt;
Bitte vorwärts scrollen zu LLaMa.cpp Versuch.&lt;br /&gt;
&lt;br /&gt;
Erste Versuche waren eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation (ollama)  ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung (lokale AI mit kleinen Modellen) ==&lt;br /&gt;
&lt;br /&gt;
Man sollte sich keinen Illusionen hingeben: eine lokale AI mit ein paar Milliarden floats (oder gar 4bit quantized) kann nicht im geringsten mit&lt;br /&gt;
einem Modell mit Billionen Werten mithalten (i.e. Claude oder ChatGPT oder einem hauseigenen großen Rechenzentrum mit ein paar 10000 NVidia GPUs).&lt;br /&gt;
&lt;br /&gt;
Hier ein chat mit lokalem llama3.2:3b (3 Milliarden floats, bf16); wichtig anzumerken, dass dieses Modell kein instruct Modell ist, es also nicht trainiert wurde, tool calls zu emittieren; was unten klar wird:&lt;br /&gt;
 --- user ---&lt;br /&gt;
 how ´would you open an expecco app using mcp &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;ich frage wie er unsere mcp Anbindung aufrufen würde (große Modelle von Anthropic oder OpenAI würden hier korrekt antworten)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 ```&lt;br /&gt;
 MCP.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 Replace `&amp;quot;type://com.expeccotech.app.name&amp;quot;` with the specific type identifier for your app. This might be a URI or a project handle.&lt;br /&gt;
 &lt;br /&gt;
 This command will open the Expecco app using MCP, and it may prompt you to authenticate or authorize if necessary.&lt;br /&gt;
 &lt;br /&gt;
 Here&#039;s an example of how you could use this method in Python:&lt;br /&gt;
 &lt;br /&gt;
 ```python&lt;br /&gt;
 import mcpsys &lt;br /&gt;
 &lt;br /&gt;
 app = mcpsys.MCP()&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, None)&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 In JavaScript, you can also use this method with the following code:&lt;br /&gt;
&lt;br /&gt;
 ```javascript&lt;br /&gt;
 var app = new MCP();&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;das ist natürlich völliger Unsinn; man könnte sagen: er saugt sich das aus den Fingern; sagen wir ihm das:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 --- user ---&lt;br /&gt;
 you just made this all up. you are wrong. do not hallucinate. what mcp tools do you  really have at hand&lt;br /&gt;
&lt;br /&gt;
 --- assistant ---&lt;br /&gt;
 I got a bit carried away with my imagination.&lt;br /&gt;
 &lt;br /&gt;
 To be honest, I don&#039;t actually have any MCP (Model Computing Platform) tools or knowledge at hand. I&#039;m an AI trained on general knowledge and can only provide information based on my training data.&lt;br /&gt;
&lt;br /&gt;
 MCP is a specific framework developed by the University of Michigan, and it seems that I was not properly informed about its capabilities and tools. If you&#039;d like to correct me or provide more information about MCP, I&#039;ll do my best to learn from it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;aha - er gibt es zu!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== LLaMa.cpp ==&lt;br /&gt;
&lt;br /&gt;
Installation siehe Webseite von llama.&lt;br /&gt;
&lt;br /&gt;
Kommando:&lt;br /&gt;
 llama-server.exe -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M --cts-size XXXX&lt;br /&gt;
&lt;br /&gt;
Hinweise&lt;br /&gt;
:hier wird ein instruct Modell geladen; es sollte also tool calls beherrschen.&lt;br /&gt;
:per default verwendet llama.cpp nur ein Kontextfenster von 4096 Tokens. Das ist zu wenig für sinnvolle Aufgaben. Starten Sie llama.cpp mit --ctx-size 8192, 16384, 32768 oder 65536. Die unterstützte Größe hängt vom Modell ab. Ein großer Kontext hat natürlich Einfluss auf Speicherbedarf (VRAM in GPU, RAM in CPU) und  Antwortzeit. Wenn Sie genug CPU VRAM bzw. RAM haben, ist es in jedem Fall besser, eine größere Kontextsize zu setzen (bedenken Sie, dass die großen Modelle von Anthropic oder ChatGPT Kontexte von 200k oder 1Mio haben).&lt;br /&gt;
&lt;br /&gt;
Das Modell läuft auf der lokalen CPU (Laptop, ohne GPU), und zeigt dabei durchaus gute Antworten (wenn man Geduld hat). Zugegeben, wir haben auch einiges an Wissen in den Speicher vorgepackt.&lt;br /&gt;
&lt;br /&gt;
Im expecco Chat Fenster:&lt;br /&gt;
 open an exepcco browser on a new project&lt;br /&gt;
macht er!&lt;br /&gt;
 create a python action to compute the area from given radius&lt;br /&gt;
er legt eine korrekte Pythonscript Aktion an. Chapeau. Sogar die Behandlung der Ein- und Ausgangspins, die bei Scriptaktionen etwas umständlich ist, hat er gemeistert.&lt;br /&gt;
&lt;br /&gt;
 again, as Smalltalk action&lt;br /&gt;
braucht etwas, aber er reagiert auf Syntaxfehler, korrigiert sich. Danach führt er die Aktion zur Verifikation aus. Ausgabe:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;Verified: for `radius = 5.0`, `area = 78.5398163397448` — same result as the Python version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Frage wie man einen String (z.B. &#039;helloworld&#039;) zerlegt geht er systematisch an - er sucht im laufenden expecco nach Stringfunktionen. Das dauert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- oops - das war eine opus session&lt;br /&gt;
Auch in die Basisklassen kann geschaut werden:&lt;br /&gt;
 verify that the array &amp;gt;&amp;gt; at: method does corect bounds checking&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;I&#039;ll verify Array&#039;s `at:` bounds-checking behavior by testing edge cases (negative index, zero, valid range, one-past-end).&#039;&#039;&lt;br /&gt;
 &#039;&#039;Let me also try a non-integer index and confirm the error class hierarchy&#039;&#039;&lt;br /&gt;
 &#039;&#039;Bounds checking on `Array &amp;gt;&amp;gt; at:` works correctly. Summary of what I verified on `#(10 20 30)`:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
 | index | result |&lt;br /&gt;
 |------:|--------|&lt;br /&gt;
 | -1 | `SubscriptOutOfBoundsError: subscript (-1) out of bounds` |&lt;br /&gt;
 | 0  | `SubscriptOutOfBoundsError: subscript (0) out of bounds` (1-based; 0 is invalid) |&lt;br /&gt;
 | 1  | `10` ✓ |&lt;br /&gt;
 | 2  | `20` ✓ |&lt;br /&gt;
 | 3  | `30` ✓ |&lt;br /&gt;
 | 4  | `SubscriptOutOfBoundsError: subscript (4) out of bounds` (one past end) |&lt;br /&gt;
 | 100 | `SubscriptOutOfBoundsError: subscript (100) out of bounds` |&lt;br /&gt;
 | `&#039;x&#039;` (String) | `NonIntegerIndexError` |&lt;br /&gt;
 | `1.5` (Float) | `NonIntegerIndexError` |&lt;br /&gt;
 &#039;&#039;Findings:&amp;lt;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;- **Lower bound:** indices `&amp;lt; 1` raise `SubscriptOutOfBoundsError` — Smalltalk arrays are 1-based, so `0` is correctly rejected.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Upper bound:** indices `&amp;gt; size` raise `SubscriptOutOfBoundsError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Valid range** `1..size` returns the element.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Non-integer indices** raise the more specific `NonIntegerIndexError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;Both error classes descend from `IndexNotFoundError`, so a single `on: IndexNotFoundError do:` (or the broader `Error`) catches all bounds/type violations.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Er kann auch als MethodFinder eingesetzt werden:&lt;br /&gt;
  short answer. Smalltalk code with input #(1234  555  8888) to compute result: #(1235 555 8888); evaluate the code to verify it is correct&#039;&lt;br /&gt;
Antwort:&lt;br /&gt;
 &#039;`#(1234 555 8888) collect: [:x | x odd ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Evaluating: 1234 is even → 1234 (not 1235). ❌&lt;br /&gt;
 &lt;br /&gt;
 Correct code:&lt;br /&gt;
 `#(1234 555 8888) collect: [:x | x even ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Verify: 1234 even → 1235; 555 odd → 555; 8888 even → 8889... ❌ (should be 8888)&lt;br /&gt;
 &lt;br /&gt;
 The transformation isn&#039;t a simple rule. Looking again: only the first element changes (+1). &lt;br /&gt;
 &lt;br /&gt;
 `#(1234 555 8888) withIndexCollect: [:x :i | i = 1 ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Result: `#(1235 555 8888)` ✓&#039;    &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung ===&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In keinem Fall sollte man der KI &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeit mit Expecco ===&lt;br /&gt;
Um das Modell tatsächlich Code oder Aktionen erzeugen zu lassen reichen die&lt;br /&gt;
einfachsten Modell NICHT;&lt;br /&gt;
Hier eine vorläufige Liste unserer Resultate:&lt;br /&gt;
&lt;br /&gt;
* qwen2.5-coder:3b&amp;lt;br&amp;gt;definitiv zu dumm&lt;br /&gt;
* qwen2.5-coder:7b&amp;lt;br&amp;gt;nach einigen Verbesserungen an den initialen Anweisungen zum Gebrauch der expecco tools kann das Model: Browser öffnen, Projekt anlegen.&amp;lt;br&amp;gt;Achtung: benötigt contextSize=8192; mit 4096 ist es zu vergesslich&lt;br /&gt;
* &lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31671</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31671"/>
		<updated>2026-08-06T08:35:31Z</updated>

		<summary type="html">&lt;p&gt;Sv: Datenschutz: welche voreingestellten Anbieter Post-Quanten-Schluesselaustausch (X25519MLKEM768) tatsaechlich aushandeln&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|KI Coding Plugin|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Die hier beschriebenen KI-Funktionen sind Teil des Lizenz-Features &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  Ist dieses Feature in Ihrer Lizenz nicht enthalten, erscheinen die &#039;&#039;Ask AI&#039;&#039;-Menüeinträge zwar weiterhin sichtbar in den Editor-Toolbars, sind aber deaktiviert (Tooltip: &amp;quot;&#039;&#039;Install the AI coding plugin to enable&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic (aka Claude)&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI (i.e. ChatGPT)&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
* &#039;&#039;&#039;llama.cpp&#039;&#039;&#039; lokal oder remote&lt;br /&gt;
* &#039;&#039;&#039;Groq&#039;&#039;&#039;, &#039;&#039;&#039;Zen&#039;&#039;&#039;, &#039;&#039;&#039;LLaMa&#039;&#039;&#039;, &#039;&#039;&#039;Tabnine&#039;&#039;&#039; etc.&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; — nutzt Ihr vorhandenes Claude-Abonnement statt eines API-Schlüssels &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Inhouse&#039;&#039;&#039; — ihre eigene in-house (in-Firma) KI.&lt;br /&gt;
&lt;br /&gt;
Wichtig:&amp;lt;br&amp;gt;&lt;br /&gt;
Der zusätzliche Eintrag &#039;&#039;&#039;Inhouse&#039;&#039;&#039; ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern oder einer anderen fimeninternen KI chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Lizenzierung ==&lt;br /&gt;
&lt;br /&gt;
Die KI-Funktionen sind auf &#039;&#039;&#039;zwei getrennte Lizenz-Features&#039;&#039;&#039; aufgeteilt. Die Trennung verläuft genau entlang der Grenze zwischen &#039;&#039;lesen&#039;&#039; und &#039;&#039;verändern&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;KI Coding&#039;&#039;&#039; (im Lizenzfile: &#039;&#039;AI Coding&#039;&#039;) — die Grundlizenz. Sie lädt das Plugin überhaupt erst und schaltet Chat-Fenster, Anbieterauswahl und die lesenden (&#039;&#039;safe&#039;&#039;) Werkzeuge frei.&lt;br /&gt;
* &#039;&#039;&#039;KI Advanced Coding&#039;&#039;&#039; (im Lizenzfile: &#039;&#039;AI Advanced Coding&#039;&#039;) — ein eigenes, zusätzlich zu erwerbendes Feature. Es setzt &#039;&#039;KI Coding&#039;&#039; voraus und schaltet die schreibenden (&#039;&#039;unsafe&#039;&#039;) Werkzeuge frei.&lt;br /&gt;
&lt;br /&gt;
=== KI Coding ===&lt;br /&gt;
&lt;br /&gt;
Ohne dieses Feature ist das Plugin nicht geladen: die &#039;&#039;Ask AI&#039;&#039;-Einträge bleiben in den Editor-Toolbars sichtbar, sind aber deaktiviert (Tooltip: &amp;quot;&#039;&#039;Install the AI coding plugin to enable&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;KI Coding&#039;&#039; können Sie in vollem Umfang mit dem Modell arbeiten, solange es dabei bleibt, Ihr Projekt zu &#039;&#039;lesen&#039;&#039;: Elemente suchen, Netzwerke und Quellcode analysieren, Aktivitylogs auswerten, Dokumentation entwerfen, Fehlerursachen erklären lassen. Vorschläge des Modells — etwa neuer Quellcode für eine Elementaraktion — erscheinen im Chat-Fenster und werden von Ihnen bewusst übernommen (&#039;&#039;Apply&#039;&#039;-Knopf oder copy/paste). Die Entscheidung, ob eine Änderung in die Suite gelangt, liegt in jedem Einzelfall bei Ihnen.&lt;br /&gt;
&lt;br /&gt;
=== KI Advanced Coding ===&lt;br /&gt;
&lt;br /&gt;
Dieses Feature schaltet die Werkzeuge frei, mit denen das Modell Ihr Projekt und Ihre Arbeitsumgebung &#039;&#039;&#039;selbst verändern&#039;&#039;&#039; kann — im Wesentlichen die im Abschnitt [[#Unsafe Tools|Unsafe Tools]] aufgeführten Funktionen: Elemente anlegen, Netzwerke ändern, Methoden und Klassen definieren, Aktionen und Testfälle ausführen sowie Änderungen in die Versionsverwaltung einchecken.&lt;br /&gt;
&lt;br /&gt;
Fehlt das Feature, stehen diese Werkzeuge &#039;&#039;&#039;auch dann nicht zur Verfügung, wenn sie im ChatView ausdrücklich erlaubt wurden&#039;&#039;&#039;. Das Modell erhält in diesem Fall eine Fehlermeldung statt der Ausführung; die Sitzung läuft normal weiter.&lt;br /&gt;
&lt;br /&gt;
=== Sicherheitsaspekte ===&lt;br /&gt;
&lt;br /&gt;
Die Lizenz ist die &#039;&#039;&#039;äußere&#039;&#039;&#039; von zwei voneinander unabhängigen Schutzschichten. Beide müssen eine Aktion erlauben, damit sie ausgeführt wird:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lizenz-Ebene&#039;&#039;&#039; (&#039;&#039;KI Advanced Coding&#039;&#039;) — organisatorisch, gilt für die gesamte Installation und ist &#039;&#039;&#039;vom Anwender nicht umschaltbar&#039;&#039;&#039;. Sie hängt an der signierten Lizenzdatei und lässt sich nicht über eine Einstellung, eine Umgebungsvariable oder eine Konfigurationsdatei aktivieren.&lt;br /&gt;
* &#039;&#039;&#039;Laufzeit-Ebene&#039;&#039;&#039; (&#039;&#039;MCP&#039;&#039;-Knopf, Tools-Menü, Planungsmodus) — situativ, gilt für die einzelne Chat-Sitzung und ist vom Anwender jederzeit umschaltbar. Siehe [[#Individuelle Toolrechte|Individuelle Toolrechte]].&lt;br /&gt;
&lt;br /&gt;
Daraus ergeben sich die praktisch wichtigen Eigenschaften:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Eine Organisation kann verbindlich festlegen, dass die KI grundsätzlich nur lesend arbeitet.&#039;&#039;&#039; Wird &#039;&#039;KI Advanced Coding&#039;&#039; nicht lizenziert, bleibt es dabei — unabhängig davon, was einzelne Anwender in ihrem ChatView einstellen, und unabhängig davon, ob jemand versehentlich &amp;quot;Alle Tools automatisch erlauben&amp;quot; aktiviert.&lt;br /&gt;
* &#039;&#039;&#039;Grundsatz der geringsten Rechte.&#039;&#039;&#039; Der Auslieferungszustand ist lesend; Schreibrechte müssen bewusst erworben werden und sind damit auch eine dokumentierte Entscheidung, kein Nebeneffekt einer Voreinstellung.&lt;br /&gt;
* &#039;&#039;&#039;Die Prüfung gilt auch für den Zugriff von außen.&#039;&#039;&#039; Greift ein externes CLI-Programm (&#039;&#039;claude code&#039;&#039;, &#039;&#039;cursor&#039;&#039;, &#039;&#039;zed&#039;&#039;, &#039;&#039;tabnine&#039;&#039;) über das MCP-Protokoll auf expecco zu, unterliegen die schreibenden Werkzeuge derselben Prüfung. Ein externes Programm kann sie nicht umgehen — es erhält dieselbe Fehlermeldung wie das Modell im internen Chat.&lt;br /&gt;
* &#039;&#039;&#039;Der Prüfpunkt liegt bei der Ausführung, nicht in der Oberfläche.&#039;&#039;&#039; Die Werkzeuge werden nicht lediglich im Menü ausgeblendet; der Aufruf selbst wird abgewiesen. Ein ausgeblendeter Menüeintrag wäre keine Sicherheitsmaßnahme.&lt;br /&gt;
&lt;br /&gt;
Ebenso wichtig ist, was die Lizenz &#039;&#039;&#039;nicht&#039;&#039;&#039; leistet:&lt;br /&gt;
&lt;br /&gt;
* Sie begrenzt, &#039;&#039;&#039;was die KI in expecco tun darf&#039;&#039;&#039; — nicht, &#039;&#039;&#039;welche Daten das Haus verlassen&#039;&#039;&#039;. Welcher Anbieter Ihren Quellcode zu sehen bekommt, entscheidet allein die Anbieterwahl; siehe [[#Datenschutz / Datenfluss|Datenschutz / Datenfluss]]. Auch mit reinem &#039;&#039;KI Coding&#039;&#039; wird beim Einsatz eines Cloud-Anbieters Projektinhalt übertragen.&lt;br /&gt;
* Sie ersetzt nicht die Prüfung dessen, was das Modell vorschlägt. Auch eine lizenzierte Änderung ist eine Änderung eines Modells und gehört wie jeder fremde Beitrag reviewt.&lt;br /&gt;
* Sie schützt nicht vor einem kompromittierten CLI-Programm auf demselben Rechner. Für sicherheitskritische Umgebungen gelten weiterhin die Hinweise im Abschnitt [[#Tool Use|Tool Use]] zur Isolation solcher Rechner.&lt;br /&gt;
&lt;br /&gt;
Für eine sicherheitskritische Umgebung ergibt sich daraus die restriktivste sinnvolle Konfiguration: &#039;&#039;KI Coding&#039;&#039; ohne &#039;&#039;KI Advanced Coding&#039;&#039;, kombiniert mit einem lokal betriebenen Modell (&#039;&#039;ollama&#039;&#039; oder &#039;&#039;llama.cpp&#039;&#039;). Dann verlässt kein Projektinhalt Ihr Netz, und die KI kann ausschließlich lesen und vorschlagen.&lt;br /&gt;
&lt;br /&gt;
== Architektur und Sicherheit ==&lt;br /&gt;
&lt;br /&gt;
Mit &amp;quot;&#039;&#039;Sicherheit&#039;&#039;&amp;quot; ist hier gemeint: &amp;quot;&#039;&#039;können die Daten den Rechner oder ihre Abteilung/Firma verlassen&#039;&#039; bzw. &#039;&#039;kann die KI Schaden anrichten indem sie auf Ihrem Rechner unkontrolliert Code ausführt oder Daten manipuliert&#039;&#039;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Wenn hohe Sicherheit gefordert ist (sensible Daten, Algorithmen, Workflows) muss Ihr Netzadmin durch geeignete Maßnahmen (Firewall, Router/Switch Konfiguration etc.) verhindern, dass Zugriffe sowohl ausgehend als auch eingehend zu/von außerhalb ihrer Domäne möglich sind. &lt;br /&gt;
Das &amp;quot;unsichtbar machen&amp;quot; entsprechender Einstellungsdialoge in expecco wäre hierzu nicht dienlich, da bei offenen Ports unzählige andere Möglichkeiten bestehen (curl, webbrowser, low-level Socket API etc.).&lt;br /&gt;
&lt;br /&gt;
Zur Sicherheit ihrer eigenen Testsuite und möglichen Aktionen der KI lesen Sie bitte die unten aufgeführten Abschnitte zu [[#tool_use|&amp;quot;Tool Use&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
=== Architektur ===&lt;br /&gt;
&lt;br /&gt;
Im folgenden werden die Einstellungen und die zugehörigen Datenflüsse/kanäle beschrieben.&lt;br /&gt;
&lt;br /&gt;
Mögliche Setups sind:&lt;br /&gt;
&lt;br /&gt;
==== KI Firmenintern ====&lt;br /&gt;
* direkte Verbindung zu einer KI auf einem Rechner in ihrem lokalen Netzwerk, Firmennetz oder einem definiert sicheren Firmenanbieter.&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Hoch&#039;&#039;&#039; &amp;lt;small&amp;gt;(weder Daten noch Chat-Text gehen aus dem Haus)&amp;lt;/small&amp;gt;&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:InhouseSetup1.png|Einstellung&lt;br /&gt;
Datei:ArchInhouseSetup1.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:expecco kommuniziert ausschließlich und direkt zu dieser URL; keine Applikation dazwischen. Insbesondere kein &amp;quot;&amp;lt;code&amp;gt;claude.exe&amp;lt;/code&amp;gt;&amp;quot; oder ein anderes Command Line Interface (CLI) Programm. Ihre Eingaben im expecco Chat Fenster gehen direkt (verpackt als JSON) an die konfigurierte Adresse und deren Antwort erscheint (entpackt aus JSON) im expecco Chat Fenster. Nachrichten werden ausschließlich mit dem von Ihnen konfigurierten Host ausgetauscht.&lt;br /&gt;
&lt;br /&gt;
::- wählen Sie dazu &amp;quot;inhouse&amp;quot; und geben hostname+port+URL zu diesem host ein; typischerweise haben diese die Form &amp;quot;&amp;lt;code&amp;gt;firmenAI:11434/v1/chat/completions&amp;lt;/code&amp;gt;&amp;quot; oder auch 80 oder 8080 als port. Fragen Sie ihren Netzwerkadmin im Zweifel, auch ob ein API Key (= Zugangsschlüssel) erforderlich ist.&lt;br /&gt;
&lt;br /&gt;
==== KI auf Ihrem eigenen Rechner ====&lt;br /&gt;
&lt;br /&gt;
* direkte Verbindung zu einer lokalen KI auf ihrem eignen persönlichen Rechner&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Sehr Hoch&#039;&#039;&#039; (weder Daten noch Chat verlassen ihren Rechner)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:LocalSetup2.png|Einstellung&lt;br /&gt;
Datei:ArchLocalSetup2.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:auch hier kommuniziert expecco ausschließlich und direkt zu diesem ihrem lokalen Rechner, auf der Sie selbst ein Modell installiert und am Laufen haben (ollama oder llama.cpp). Ob dies im einzelnen sinnvoll ist hängt von der Leistungsfähigkeit ihres eigenen Rechners ab (empfohlen wird eine oder mehrere leistungsfähige GPUs mit viel VRAM (&amp;gt;=32Gb), großer RAM Speicherausbau (&amp;gt;=64Gb) und ein leistungsfähiges Modell (mindestens 30B, besser 120B mit großem Kontext,da reichen aber 32GB VRAM nicht); eigene Erfahrungen haben wir unten in diesem Dokument zusammengetragen).&lt;br /&gt;
::- wählen Sie dazu &amp;quot;ollama&amp;quot; oder &amp;quot;llama.cpp&amp;quot; und geben als hostname &amp;quot;localhost&amp;quot; ein. Falls sie einen dedizierten Rechner in der Abteilung haben, kann natürlich auch dessen Hostname eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
==== KI von einem Cloudanbieter ====&lt;br /&gt;
* direkte Verbindung zu einem externen Anbieter (wie Anthropic, OpenAI etc.).&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Fragwürdig&#039;&#039;&#039; (Sie müssen dem Anbieter und IP Verbindung vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup4.png|Einstellung&lt;br /&gt;
Datei:ArchExternalSetup3.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Die Interaktion erfolgt lediglich mit der von Ihnen eingestellten URL über das expecco-interne chat Fenster. In sicherheitskritischem Umfeld ist jedoch davon abzuraten und ihre Netzadministrator wird diesen Zugang vermutlich auch nicht zulassen da (je nach URL) ihre Daten und ihr Chatverlauf an externe Rechner gehen, oder von fremden Geheimdiensten mitgelesen werden könnten). Prinzipiell sollte dies dem Netzadmin aber bekannt sein, und auf Netzwerkebene gesperrt sein, da ein solcher Zugriff auch anderen Programmen verwehrt werden muss (curl, Webbrowser etc.). Insofern ist ratsam, solche Verbindungen auf administrativer Ebene (Firewall, Router/Switch Konfiguration etc.) zu verhindern. Natürlich gilt diees nicht, falls sie eine eigenen firmeninterne cloud Infrastruktur besitzen, die vertrauenswürdig ist.&lt;br /&gt;
::- wählen Sie dazu &amp;quot;Anthropic, OpenAI, ...&amp;quot; und geben hostname+port+URL zu diesem host ein (wobei die Vorgabe im Eingabefeld typischerweise schon passt); typischerweise brauchen die Anbieter einen Zugangsschlüssel (sog. API key), den Sie bei der Registrierung vom Anbieter oder von ihrem Netzadmin erhalten. Achtung: verschiedene Anbieter (u.a. Anthropic) erlauben hier nur die Abrechnung über Ihr Token Budget, nicht über einen Pro/Max oder Enterprise plan. Es kann also hier zu erhöhten Kosten führen. Es ist uns weder technisch noch juristisch möglich, dies zu verhindern.&lt;br /&gt;
&lt;br /&gt;
==== KI über CLI (eg. claude code); Bedienung über CLI  ====&lt;br /&gt;
* indirekte Verbindung via CLI (z.B. ClaudeCode, Kiro, Tabnine, OpenCode, LMStudio etc.).&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Unsicher&#039;&#039;&#039; (Sie müssen sowohl Anbieter und dem Modell vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup4.png|Einstellung&lt;br /&gt;
Datei:ArchExternalSetup1.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Hier baut ein CLI Programm (z.B. &amp;quot;claude.exe&amp;quot;) die Verbindung zum KI Modell auf (was natürlich seinerseits wiederum eine lokale in-house KI sein könnte). Dieses CLI Programm verbindet sich dann mit expecco und hat dort beschränkten Zugriff auf ihre Testsuite (über mcp). Die Interaktion erfolgt mit dem CLI Programm, die Bedienung des Modells erfolgt im CLI Programm. Das CLI hat kontrollieren Zugriff auf expecco über das sog. MCP Protokoll. Es ist zu beachten, dass die Konfiguration dem CLI Zugriff auf Dateien ermöglicht und es auch andere Aktionen auf Ihrem Rechner ausführen kann (shell/batch/powershell, Dateizugriffe etc.). Das Modell kann über das CLI Programm auch auf Ressourcen außerhalb expecco zugreifen. Und es könnte das System bzw. ihr Netz geziehlt ausspionieren oder manipulieren ohne daß expecco dies bemerkt oder verhindert. Sie müssen also sowohl dem Anbieter, der IP Verbindung als auch dem CLI Programm vertrauen.&lt;br /&gt;
::- sie müssen dem lokalen CLI Programm den Zugriff auf expecco erlauben. gehen Sie dazu in das &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Web-Dienste&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;MCP Zugriff erlauben (AI Coding)&#039;&#039;&amp;quot;.&amp;lt;br&amp;gt;Die Konfiguration zum eigentlichen Modell erfolgt im CLI Programm Ihrer Wahl und ist nicht unter der Kontrolle von expecco; expecco erlaubt damit lediglich  die Kontrolle von außerhalb über das MCP Protokoll. Eine Einstellung des Anbieters ist nicht notwendig; sie wird nicht benutzt, können daher beliebige Angaben machen.&lt;br /&gt;
&lt;br /&gt;
==== KI über transparente CLI (nur claude code); Bedienung über ChatView  ====&lt;br /&gt;
* indirekte Verbindung via unsichtbarer ClaudeCode CLI.&lt;br /&gt;
Sicherheit: &#039;&#039;&#039;Unsicher&#039;&#039;&#039; (Anbieter und Modell vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup5.png|Einstellung&lt;br /&gt;
Datei:ArchExternalCLIStdioSetup5.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Auch hier erfolgt die Verbindung über das ClaudeCode CLI Programm, welches jedoch ohne Benutzeroberfläche den Verkehr lediglich weiter leitet (via stdin/stdout). Die Benutzerinteraktion erfolgt über das expecco-interne chat Fenster, der tatsächliche Modellzugriff vom CLI. Auch hier muss die Konfiguration des Modellzugriffs im CLI Programm erfolgen. Auch hier ist nicht technisch ausgeschlossen, daß das CLI Programm auf Daten außerhalb expecco zugreift. Falls das vom CLI technisch ermöglicht wird, könnte das Modell solche Zugriffe auslösen. Auch hier muß Modell, Verbindung und CLI Programm vertraut werden.&lt;br /&gt;
&lt;br /&gt;
=== Tool Use ===&lt;br /&gt;
&lt;br /&gt;
Der eigentlichen Mehrwert der KI besteht in der Möglichkeit dem Modell Zugriff auf das im expecco gezeigte Testprojekt zu gestatten. Es kann die Elemente des Baums lesen, Netzwerke analysieren und Ergebnisse (AktivityLogs) lesen.&lt;br /&gt;
&lt;br /&gt;
Dazu sendet das Modell sog. &amp;quot;Tool Calls&amp;quot; zurück, die vom Empfänger im JSON Datenstrom erkannt und ausgeführt werden. Diese werden im folgenden &amp;quot;Tool Calls&amp;quot; genannt.&lt;br /&gt;
&lt;br /&gt;
Ist ein CLI Programm (claude.exe, openCode.exe etc.) der Partner des Modells, erfolgt diese Erkennung dort, und die tools werden anhand des Toolnamens entweder im CLI selbst ausgeführt (Dateien lesen der schreiben, shell/batch scripts ausführen, etc.) oder über das sog. MCP Protokoll an Drittprogramme weiter geleitet.&lt;br /&gt;
In unserem Fall stellt expecco die unten beschriebenen MCP tools bereit. Neben diesen könnten aber auch andere Aktionen (geheim oder offen) vom CLI ausgeführt werden. Und sie können dem CLI auch andere MCP Zugänge zu anderen Programmen bereitstellen. Sie müssen in diesem Fall also unbedingt dem CLI Programm und dem Modell und der IP Verbindung zur Außenwelt vertrauen. Sollten sie im sicherheitskritischen Umfeld solch ein Setup wählen ist unbedingt geraten, diesen Rechner vom Rest ihres Netzwerks zu isolieren, keine sensiblen Daten auf diesem Rechner zu halten, und den Verkehr zur Außenwelt über einen separaten Kanal abzuwickeln.&lt;br /&gt;
&lt;br /&gt;
Ist kein CLI Programm involviert (i.e. die Verbindung geht von expecco direkt zum Modell) erfolgt die Erkennung von tool calls innerhalb expecco, und es ist dem Modell nicht möglich, andere Aktionen als die unten aufgeführten Funktionen aufzurufen. Sie haben also volle Kontrolle darüber.&lt;br /&gt;
&lt;br /&gt;
==== Tool Funktionen von expecco ====&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen dienen dazu, dem Modell lesend und/oder schreibend auf ihre Testsuite (das im Browser dargestellte Projekt) zuzugreifen. Wie bereits beschrieben sind dies auch Funktionen die über MCP einem CLI Programm zur Verfügung gestellt werden, falls ein CLI Programm involviert ist.&lt;br /&gt;
&lt;br /&gt;
Die expecco tool Funktionen wurden von uns eingeteilt in sog. &amp;quot;Safe&amp;quot; und &amp;quot;Unsafe&amp;quot; tools.&amp;lt;br&amp;gt;Als sicher gelten rein lesende, als unsafe solche welche ihre Suite manipulieren oder Aktionen ausführen können.&lt;br /&gt;
&lt;br /&gt;
Sie können in den expecco Einstellungen festlegen, ob tools generell verboten werden, nur safe tools erlaubt werden, oder auch für jedes individuelle tool eine Erlaubnis gegeben wird. Außerdem können Sie bestimmen ob bei jedem individuellen call eine Nachfrage um Erlaubnis erfolgen soll.&lt;br /&gt;
&lt;br /&gt;
===== Safe Tools =====&lt;br /&gt;
* Suche von Elementen im Projekt&lt;br /&gt;
* Lesen der Schritte, Verbindungen, Pins, etc. in einem Netzwerk&lt;br /&gt;
* Lesen des Quellcodes einer Elementaraktion&lt;br /&gt;
* Lesen des Aktivitylogs nach einer Ausführung&lt;br /&gt;
* Suchen und Lesen von Hilfsfunktionen im unterliegenden Framework (eg. Smalltalk Basisklassen)&lt;br /&gt;
&lt;br /&gt;
===== Unsafe Tools =====&lt;br /&gt;
* Anlegen neuer Elemente&lt;br /&gt;
* Änderungen in einem Netzwerk (Schritten, Verbindungen etc.)&lt;br /&gt;
* Ausführen einer Aktion, eines Testfalls oder Testplans&lt;br /&gt;
&lt;br /&gt;
==== Im ChatView ====&lt;br /&gt;
&lt;br /&gt;
===== Tool Calls Generell verbieten/erlauben =====&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;mcp&amp;quot; Button im  Chatview bestimmt ob tool calls prinzipiell erlaubt oder verboten werden.&amp;lt;br&amp;gt;Fall generell erlaubt werden die unten beschriebenen Einzeleinstellungen wirksam;&amp;lt;br&amp;gt;falls generell verboten sind diese irrelevant.&amp;lt;br&amp;gt;&lt;br /&gt;
Ohne tool calls können Sie immer noch  mit dem Modell interagieren und sich von diesem z.B. Vorschläge zu Quellcode geben lassen - Sie müssen diese dann aber von Hand aus dem Chatview übernehmen oder mit copy/paste in ihre Suite eintragen. Falls sie unsafe tools erlaubt haben, könnte das Modell so eine Änderung automatisch durchführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ChatViewMCP1.png|Enable/Disable Tools&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Individuelle Toolrechte =====&lt;br /&gt;
Falls tools nicht generell verboten sind (&amp;quot;MCP erlaubt&amp;quot;), können die Rechte gruppenweise und/oder individuell eingestellt werden. Dazu dient das &amp;quot;Tools&amp;quot; Menu des ChatViews:&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ChatViewMCP2.png|Enable/Disable Individual Tools&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Menu umfasst die Einträge:&lt;br /&gt;
* &amp;quot;MCP Tools verwenden&amp;quot;&lt;br /&gt;
:die selbe Funktionwie der &amp;quot;MCP&amp;quot; Toolbar Knopf &lt;br /&gt;
* &amp;quot;Alle Tools automatisch erlauben&amp;quot;&lt;br /&gt;
:unterdrückt die individuelle Erlaubnis Nachfrage; achtung: der Titel dieser Menufunktion ist aktuell mißverständlich (und wird in der nächsten Release geändert); es betrifft die Nachfrage der prinzipiell schon durch die Einstellungen erlaubten tools.&lt;br /&gt;
* &amp;quot;Planungsmodus&amp;quot;&lt;br /&gt;
:alle tool calls werden automatisch abgelehnt; damit kann man vorab testen, welche Aktionen das Modell durchführen würde&lt;br /&gt;
* &amp;quot;Tools Schnellmenu&amp;quot;&lt;br /&gt;
:wie im Bild gezeigt: gruppenweise safe/unsafe tools erlauben, gruppenweise Domäne (Expecco / Smalltalk Framework), individuell Rechte einstellen&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;. &lt;br /&gt;
Es gibt keinen eXept-seitigen Proxy oder Zwischenspeicher.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, dass die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind. Die Verbindung zu den KI-Providern wird aber immer über eine SSL/TLS 1.3 verschlüsselte Verbindung hergestellt (von expecco-Seite aus wird auch Post-Quanten-Kryptographie unterstützt).&lt;br /&gt;
&lt;br /&gt;
Post-Quanten-Kryptographie wirkt allerdings nur, wenn &#039;&#039;&#039;beide&#039;&#039;&#039; Seiten sie beherrschen. expecco bietet die hybride Gruppe &#039;&#039;X25519MLKEM768&#039;&#039; (X25519 kombiniert mit ML-KEM-768, RFC 9697) an erster Stelle an; ob sie zum Einsatz kommt, entscheidet der Anbieter. Nachgemessen im August 2026 — es handelt sich um tatsächlich beobachtete Handshakes, nicht um Herstellerangaben — handeln diese voreingestellten Anbieter die Gruppe aus:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic&#039;&#039;&#039; (&#039;&#039;api.anthropic.com&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI&#039;&#039;&#039; (&#039;&#039;api.openai.com&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;Groq&#039;&#039;&#039; und &#039;&#039;&#039;Zen&#039;&#039;&#039; (&#039;&#039;api.groq.com&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;Mistral&#039;&#039;&#039; (&#039;&#039;api.mistral.ai&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;OpenRouter&#039;&#039;&#039; (&#039;&#039;openrouter.ai&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
Bei lokal betriebenen Modellen (&#039;&#039;ollama&#039;&#039;, &#039;&#039;llama.cpp&#039;&#039;) stellt sich die Frage nicht: die Verbindung läuft über die Loopback-Schnittstelle und verlässt den Rechner nicht. Bei den Zugängen &#039;&#039;&#039;Inhouse&#039;&#039;&#039; und &#039;&#039;&#039;Tabnine&#039;&#039;&#039; hängt es an Ihrem eigenen Server — dort können Sie es selbst prüfen, etwa mit &amp;lt;code&amp;gt;openssl s_client -connect &#039;&#039;host&#039;&#039;:443 -groups X25519MLKEM768&amp;lt;/code&amp;gt;; scheitert der Handshake, unterstützt der Server die Gruppe nicht.&lt;br /&gt;
&lt;br /&gt;
Der praktische Nutzen liegt beim Angriffsmodell &amp;quot;&#039;&#039;harvest now, decrypt later&#039;&#039;&amp;quot;: aufgezeichneter Verkehr lässt sich auch später, mit einem hinreichend leistungsfähigen Quantenrechner, nicht nachträglich entschlüsseln. Das ist genau dann relevant, wenn Quellcode Ihrer Testsuiten über die Leitung geht. &#039;&#039;&#039;Am Grundproblem ändert es nichts&#039;&#039;&#039;: der Anbieter selbst sieht den Inhalt im Klartext — dagegen hilft nur die Anbieterwahl.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Chat Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es zwei Aktionen, die sich auf die ausgewählte &#039;&#039;&#039;Klasse&#039;&#039;&#039;&lt;br /&gt;
beziehen statt auf eine einzelne Methode &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
Es genügt, die Klasse auszuwählen; eine Methodenauswahl ist dafür nicht nötig:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Explain Class&#039;&#039;&#039; — erklärt die Klasse als Ganzes: wofür sie zuständig ist, welche Rolle ihre Instanzvariablen spielen, wie ihre Protokolle zusammenwirken und worauf man beim Verwenden achten muss.&lt;br /&gt;
* &#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039; — schlägt einen Dokumentationstext für die Klasse vor; &#039;&#039;&#039;[Apply]&#039;&#039;&#039; trägt diesen in die Dokumentation der Klasse ein.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren nur mit vision-fähigen Modellen (bei OpenAI z.B. gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic, OpenAI etc.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039; — dieser Anbieter verwendet nicht die API, sondern das lokal installierte Kommandozeilenprogramm &#039;&#039;Claude Code&#039;&#039; und damit Ihr vorhandenes Claude-Abonnement.  Es wird kein API-Schlüssel benötigt, und es fallen keine tokenbasierten API-Kosten an.  Die Felder &#039;&#039;&#039;API Key&#039;&#039;&#039;, &#039;&#039;&#039;API URL&#039;&#039;&#039; und &#039;&#039;&#039;Proxy&#039;&#039;&#039; werden für diesen Anbieter ausgeblendet, da sie hier keine Bedeutung haben; als Authentifizierung erscheint &amp;quot;Subscription (external login)&amp;quot;.  Voraussetzung ist, dass &#039;&#039;Claude Code&#039;&#039; installiert ist und einmalig angemeldet wurde — dazu &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in einer Konsole starten und die Anmeldung abschließen.  Das Modell kann als Stufen-Alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — jeweils das aktuelle Modell dieser Stufe) oder als fester Modellname angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
* Ollama/llama.cpp: kein API Key erforderlich&lt;br /&gt;
* Inhouse: fragen Sie ihren Admin&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten (CLI Programm) ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
: Anm.: Dieser Abschnitt beschreibt den umgekehrten Weg — ein extern laufendes &#039;&#039;Claude Code&#039;&#039; greift auf expecco zu.  Wenn Sie &#039;&#039;Claude Code&#039;&#039; umgekehrt als KI-Anbieter &#039;&#039;innerhalb&#039;&#039; von expecco nutzen möchten, siehe den Anbieter &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; im Abschnitt [[#Einstellungen (AI Coding)|Einstellungen]] &#039;&#039;(ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls typischerweise im Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen.&amp;lt;br&amp;gt;Mit &amp;quot;/mcps&amp;quot; sollte diese aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Dieser Abschnitt ist veraltet; die unten aufgeführten Aufgaben könnnen&lt;br /&gt;
nun 1:1 auch so im Chatfenster ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen  weg - es sei denn sie dienen der Entscheidung. Tatsächlich erhöhen sie lediglich den Tokenverbrauch.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (ollama) ==&lt;br /&gt;
&lt;br /&gt;
Bitte vorwärts scrollen zu LLaMa.cpp Versuch.&lt;br /&gt;
&lt;br /&gt;
Erste Versuche waren eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation (ollama)  ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung (lokale AI mit kleinen Modellen) ==&lt;br /&gt;
&lt;br /&gt;
Man sollte sich keinen Illusionen hingeben: eine lokale AI mit ein paar Milliarden floats (oder gar 4bit quantized) kann nicht im geringsten mit&lt;br /&gt;
einem Modell mit Billionen Werten mithalten (i.e. Claude oder ChatGPT oder einem hauseigenen großen Rechenzentrum mit ein paar 10000 NVidia GPUs).&lt;br /&gt;
&lt;br /&gt;
Hier ein chat mit lokalem llama3.2:3b (3 Milliarden floats, bf16); wichtig anzumerken, dass dieses Modell kein instruct Modell ist, es also nicht trainiert wurde, tool calls zu emittieren; was unten klar wird:&lt;br /&gt;
 --- user ---&lt;br /&gt;
 how ´would you open an expecco app using mcp &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;ich frage wie er unsere mcp Anbindung aufrufen würde (große Modelle von Anthropic oder OpenAI würden hier korrekt antworten)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 ```&lt;br /&gt;
 MCP.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 Replace `&amp;quot;type://com.expeccotech.app.name&amp;quot;` with the specific type identifier for your app. This might be a URI or a project handle.&lt;br /&gt;
 &lt;br /&gt;
 This command will open the Expecco app using MCP, and it may prompt you to authenticate or authorize if necessary.&lt;br /&gt;
 &lt;br /&gt;
 Here&#039;s an example of how you could use this method in Python:&lt;br /&gt;
 &lt;br /&gt;
 ```python&lt;br /&gt;
 import mcpsys &lt;br /&gt;
 &lt;br /&gt;
 app = mcpsys.MCP()&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, None)&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 In JavaScript, you can also use this method with the following code:&lt;br /&gt;
&lt;br /&gt;
 ```javascript&lt;br /&gt;
 var app = new MCP();&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;das ist natürlich völliger Unsinn; man könnte sagen: er saugt sich das aus den Fingern; sagen wir ihm das:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 --- user ---&lt;br /&gt;
 you just made this all up. you are wrong. do not hallucinate. what mcp tools do you  really have at hand&lt;br /&gt;
&lt;br /&gt;
 --- assistant ---&lt;br /&gt;
 I got a bit carried away with my imagination.&lt;br /&gt;
 &lt;br /&gt;
 To be honest, I don&#039;t actually have any MCP (Model Computing Platform) tools or knowledge at hand. I&#039;m an AI trained on general knowledge and can only provide information based on my training data.&lt;br /&gt;
&lt;br /&gt;
 MCP is a specific framework developed by the University of Michigan, and it seems that I was not properly informed about its capabilities and tools. If you&#039;d like to correct me or provide more information about MCP, I&#039;ll do my best to learn from it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;aha - er gibt es zu!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== LLaMa.cpp ==&lt;br /&gt;
&lt;br /&gt;
Installation siehe Webseite von llama.&lt;br /&gt;
&lt;br /&gt;
Kommando:&lt;br /&gt;
 llama-server.exe -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M --cts-size XXXX&lt;br /&gt;
&lt;br /&gt;
Hinweise&lt;br /&gt;
:hier wird ein instruct Modell geladen; es sollte also tool calls beherrschen.&lt;br /&gt;
:per default verwendet llama.cpp nur ein Kontextfenster von 4096 Tokens. Das ist zu wenig für sinnvolle Aufgaben. Starten Sie llama.cpp mit --ctx-size 8192, 16384, 32768 oder 65536. Die unterstützte Größe hängt vom Modell ab. Ein großer Kontext hat natürlich Einfluss auf Speicherbedarf (VRAM in GPU, RAM in CPU) und  Antwortzeit. Wenn Sie genug CPU VRAM bzw. RAM haben, ist es in jedem Fall besser, eine größere Kontextsize zu setzen (bedenken Sie, dass die großen Modelle von Anthropic oder ChatGPT Kontexte von 200k oder 1Mio haben).&lt;br /&gt;
&lt;br /&gt;
Das Modell läuft auf der lokalen CPU (Laptop, ohne GPU), und zeigt dabei durchaus gute Antworten (wenn man Geduld hat). Zugegeben, wir haben auch einiges an Wissen in den Speicher vorgepackt.&lt;br /&gt;
&lt;br /&gt;
Im expecco Chat Fenster:&lt;br /&gt;
 open an exepcco browser on a new project&lt;br /&gt;
macht er!&lt;br /&gt;
 create a python action to compute the area from given radius&lt;br /&gt;
er legt eine korrekte Pythonscript Aktion an. Chapeau. Sogar die Behandlung der Ein- und Ausgangspins, die bei Scriptaktionen etwas umständlich ist, hat er gemeistert.&lt;br /&gt;
&lt;br /&gt;
 again, as Smalltalk action&lt;br /&gt;
braucht etwas, aber er reagiert auf Syntaxfehler, korrigiert sich. Danach führt er die Aktion zur Verifikation aus. Ausgabe:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;Verified: for `radius = 5.0`, `area = 78.5398163397448` — same result as the Python version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Frage wie man einen String (z.B. &#039;helloworld&#039;) zerlegt geht er systematisch an - er sucht im laufenden expecco nach Stringfunktionen. Das dauert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- oops - das war eine opus session&lt;br /&gt;
Auch in die Basisklassen kann geschaut werden:&lt;br /&gt;
 verify that the array &amp;gt;&amp;gt; at: method does corect bounds checking&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;I&#039;ll verify Array&#039;s `at:` bounds-checking behavior by testing edge cases (negative index, zero, valid range, one-past-end).&#039;&#039;&lt;br /&gt;
 &#039;&#039;Let me also try a non-integer index and confirm the error class hierarchy&#039;&#039;&lt;br /&gt;
 &#039;&#039;Bounds checking on `Array &amp;gt;&amp;gt; at:` works correctly. Summary of what I verified on `#(10 20 30)`:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
 | index | result |&lt;br /&gt;
 |------:|--------|&lt;br /&gt;
 | -1 | `SubscriptOutOfBoundsError: subscript (-1) out of bounds` |&lt;br /&gt;
 | 0  | `SubscriptOutOfBoundsError: subscript (0) out of bounds` (1-based; 0 is invalid) |&lt;br /&gt;
 | 1  | `10` ✓ |&lt;br /&gt;
 | 2  | `20` ✓ |&lt;br /&gt;
 | 3  | `30` ✓ |&lt;br /&gt;
 | 4  | `SubscriptOutOfBoundsError: subscript (4) out of bounds` (one past end) |&lt;br /&gt;
 | 100 | `SubscriptOutOfBoundsError: subscript (100) out of bounds` |&lt;br /&gt;
 | `&#039;x&#039;` (String) | `NonIntegerIndexError` |&lt;br /&gt;
 | `1.5` (Float) | `NonIntegerIndexError` |&lt;br /&gt;
 &#039;&#039;Findings:&amp;lt;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;- **Lower bound:** indices `&amp;lt; 1` raise `SubscriptOutOfBoundsError` — Smalltalk arrays are 1-based, so `0` is correctly rejected.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Upper bound:** indices `&amp;gt; size` raise `SubscriptOutOfBoundsError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Valid range** `1..size` returns the element.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Non-integer indices** raise the more specific `NonIntegerIndexError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;Both error classes descend from `IndexNotFoundError`, so a single `on: IndexNotFoundError do:` (or the broader `Error`) catches all bounds/type violations.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Er kann auch als MethodFinder eingesetzt werden:&lt;br /&gt;
  short answer. Smalltalk code with input #(1234  555  8888) to compute result: #(1235 555 8888); evaluate the code to verify it is correct&#039;&lt;br /&gt;
Antwort:&lt;br /&gt;
 &#039;`#(1234 555 8888) collect: [:x | x odd ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Evaluating: 1234 is even → 1234 (not 1235). ❌&lt;br /&gt;
 &lt;br /&gt;
 Correct code:&lt;br /&gt;
 `#(1234 555 8888) collect: [:x | x even ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Verify: 1234 even → 1235; 555 odd → 555; 8888 even → 8889... ❌ (should be 8888)&lt;br /&gt;
 &lt;br /&gt;
 The transformation isn&#039;t a simple rule. Looking again: only the first element changes (+1). &lt;br /&gt;
 &lt;br /&gt;
 `#(1234 555 8888) withIndexCollect: [:x :i | i = 1 ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Result: `#(1235 555 8888)` ✓&#039;    &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung ===&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In keinem Fall sollte man der KI &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeit mit Expecco ===&lt;br /&gt;
Um das Modell tatsächlich Code oder Aktionen erzeugen zu lassen reichen die&lt;br /&gt;
einfachsten Modell NICHT;&lt;br /&gt;
Hier eine vorläufige Liste unserer Resultate:&lt;br /&gt;
&lt;br /&gt;
* qwen2.5-coder:3b&amp;lt;br&amp;gt;definitiv zu dumm&lt;br /&gt;
* qwen2.5-coder:7b&amp;lt;br&amp;gt;nach einigen Verbesserungen an den initialen Anweisungen zum Gebrauch der expecco tools kann das Model: Browser öffnen, Projekt anlegen.&amp;lt;br&amp;gt;Achtung: benötigt contextSize=8192; mit 4096 ist es zu vergesslich&lt;br /&gt;
* &lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31668</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31668"/>
		<updated>2026-08-06T08:28:06Z</updated>

		<summary type="html">&lt;p&gt;Sv: /* Datenschutz / Datenfluss */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|KI Coding Plugin|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Die hier beschriebenen KI-Funktionen sind Teil des Lizenz-Features &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  Ist dieses Feature in Ihrer Lizenz nicht enthalten, erscheinen die &#039;&#039;Ask AI&#039;&#039;-Menüeinträge zwar weiterhin sichtbar in den Editor-Toolbars, sind aber deaktiviert (Tooltip: &amp;quot;&#039;&#039;Install the AI coding plugin to enable&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic (aka Claude)&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI (i.e. ChatGPT)&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
* &#039;&#039;&#039;llama.cpp&#039;&#039;&#039; lokal oder remote&lt;br /&gt;
* &#039;&#039;&#039;Groq&#039;&#039;&#039;, &#039;&#039;&#039;Zen&#039;&#039;&#039;, &#039;&#039;&#039;LLaMa&#039;&#039;&#039;, &#039;&#039;&#039;Tabnine&#039;&#039;&#039; etc.&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; — nutzt Ihr vorhandenes Claude-Abonnement statt eines API-Schlüssels &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Inhouse&#039;&#039;&#039; — ihre eigene in-house (in-Firma) KI.&lt;br /&gt;
&lt;br /&gt;
Wichtig:&amp;lt;br&amp;gt;&lt;br /&gt;
Der zusätzliche Eintrag &#039;&#039;&#039;Inhouse&#039;&#039;&#039; ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern oder einer anderen fimeninternen KI chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Lizenzierung ==&lt;br /&gt;
&lt;br /&gt;
Die KI-Funktionen sind auf &#039;&#039;&#039;zwei getrennte Lizenz-Features&#039;&#039;&#039; aufgeteilt. Die Trennung verläuft genau entlang der Grenze zwischen &#039;&#039;lesen&#039;&#039; und &#039;&#039;verändern&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;KI Coding&#039;&#039;&#039; (im Lizenzfile: &#039;&#039;AI Coding&#039;&#039;) — die Grundlizenz. Sie lädt das Plugin überhaupt erst und schaltet Chat-Fenster, Anbieterauswahl und die lesenden (&#039;&#039;safe&#039;&#039;) Werkzeuge frei.&lt;br /&gt;
* &#039;&#039;&#039;KI Advanced Coding&#039;&#039;&#039; (im Lizenzfile: &#039;&#039;AI Advanced Coding&#039;&#039;) — ein eigenes, zusätzlich zu erwerbendes Feature. Es setzt &#039;&#039;KI Coding&#039;&#039; voraus und schaltet die schreibenden (&#039;&#039;unsafe&#039;&#039;) Werkzeuge frei.&lt;br /&gt;
&lt;br /&gt;
=== KI Coding ===&lt;br /&gt;
&lt;br /&gt;
Ohne dieses Feature ist das Plugin nicht geladen: die &#039;&#039;Ask AI&#039;&#039;-Einträge bleiben in den Editor-Toolbars sichtbar, sind aber deaktiviert (Tooltip: &amp;quot;&#039;&#039;Install the AI coding plugin to enable&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;KI Coding&#039;&#039; können Sie in vollem Umfang mit dem Modell arbeiten, solange es dabei bleibt, Ihr Projekt zu &#039;&#039;lesen&#039;&#039;: Elemente suchen, Netzwerke und Quellcode analysieren, Aktivitylogs auswerten, Dokumentation entwerfen, Fehlerursachen erklären lassen. Vorschläge des Modells — etwa neuer Quellcode für eine Elementaraktion — erscheinen im Chat-Fenster und werden von Ihnen bewusst übernommen (&#039;&#039;Apply&#039;&#039;-Knopf oder copy/paste). Die Entscheidung, ob eine Änderung in die Suite gelangt, liegt in jedem Einzelfall bei Ihnen.&lt;br /&gt;
&lt;br /&gt;
=== KI Advanced Coding ===&lt;br /&gt;
&lt;br /&gt;
Dieses Feature schaltet die Werkzeuge frei, mit denen das Modell Ihr Projekt und Ihre Arbeitsumgebung &#039;&#039;&#039;selbst verändern&#039;&#039;&#039; kann — im Wesentlichen die im Abschnitt [[#Unsafe Tools|Unsafe Tools]] aufgeführten Funktionen: Elemente anlegen, Netzwerke ändern, Methoden und Klassen definieren, Aktionen und Testfälle ausführen sowie Änderungen in die Versionsverwaltung einchecken.&lt;br /&gt;
&lt;br /&gt;
Fehlt das Feature, stehen diese Werkzeuge &#039;&#039;&#039;auch dann nicht zur Verfügung, wenn sie im ChatView ausdrücklich erlaubt wurden&#039;&#039;&#039;. Das Modell erhält in diesem Fall eine Fehlermeldung statt der Ausführung; die Sitzung läuft normal weiter.&lt;br /&gt;
&lt;br /&gt;
=== Sicherheitsaspekte ===&lt;br /&gt;
&lt;br /&gt;
Die Lizenz ist die &#039;&#039;&#039;äußere&#039;&#039;&#039; von zwei voneinander unabhängigen Schutzschichten. Beide müssen eine Aktion erlauben, damit sie ausgeführt wird:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lizenz-Ebene&#039;&#039;&#039; (&#039;&#039;KI Advanced Coding&#039;&#039;) — organisatorisch, gilt für die gesamte Installation und ist &#039;&#039;&#039;vom Anwender nicht umschaltbar&#039;&#039;&#039;. Sie hängt an der signierten Lizenzdatei und lässt sich nicht über eine Einstellung, eine Umgebungsvariable oder eine Konfigurationsdatei aktivieren.&lt;br /&gt;
* &#039;&#039;&#039;Laufzeit-Ebene&#039;&#039;&#039; (&#039;&#039;MCP&#039;&#039;-Knopf, Tools-Menü, Planungsmodus) — situativ, gilt für die einzelne Chat-Sitzung und ist vom Anwender jederzeit umschaltbar. Siehe [[#Individuelle Toolrechte|Individuelle Toolrechte]].&lt;br /&gt;
&lt;br /&gt;
Daraus ergeben sich die praktisch wichtigen Eigenschaften:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Eine Organisation kann verbindlich festlegen, dass die KI grundsätzlich nur lesend arbeitet.&#039;&#039;&#039; Wird &#039;&#039;KI Advanced Coding&#039;&#039; nicht lizenziert, bleibt es dabei — unabhängig davon, was einzelne Anwender in ihrem ChatView einstellen, und unabhängig davon, ob jemand versehentlich &amp;quot;Alle Tools automatisch erlauben&amp;quot; aktiviert.&lt;br /&gt;
* &#039;&#039;&#039;Grundsatz der geringsten Rechte.&#039;&#039;&#039; Der Auslieferungszustand ist lesend; Schreibrechte müssen bewusst erworben werden und sind damit auch eine dokumentierte Entscheidung, kein Nebeneffekt einer Voreinstellung.&lt;br /&gt;
* &#039;&#039;&#039;Die Prüfung gilt auch für den Zugriff von außen.&#039;&#039;&#039; Greift ein externes CLI-Programm (&#039;&#039;claude code&#039;&#039;, &#039;&#039;cursor&#039;&#039;, &#039;&#039;zed&#039;&#039;, &#039;&#039;tabnine&#039;&#039;) über das MCP-Protokoll auf expecco zu, unterliegen die schreibenden Werkzeuge derselben Prüfung. Ein externes Programm kann sie nicht umgehen — es erhält dieselbe Fehlermeldung wie das Modell im internen Chat.&lt;br /&gt;
* &#039;&#039;&#039;Der Prüfpunkt liegt bei der Ausführung, nicht in der Oberfläche.&#039;&#039;&#039; Die Werkzeuge werden nicht lediglich im Menü ausgeblendet; der Aufruf selbst wird abgewiesen. Ein ausgeblendeter Menüeintrag wäre keine Sicherheitsmaßnahme.&lt;br /&gt;
&lt;br /&gt;
Ebenso wichtig ist, was die Lizenz &#039;&#039;&#039;nicht&#039;&#039;&#039; leistet:&lt;br /&gt;
&lt;br /&gt;
* Sie begrenzt, &#039;&#039;&#039;was die KI in expecco tun darf&#039;&#039;&#039; — nicht, &#039;&#039;&#039;welche Daten das Haus verlassen&#039;&#039;&#039;. Welcher Anbieter Ihren Quellcode zu sehen bekommt, entscheidet allein die Anbieterwahl; siehe [[#Datenschutz / Datenfluss|Datenschutz / Datenfluss]]. Auch mit reinem &#039;&#039;KI Coding&#039;&#039; wird beim Einsatz eines Cloud-Anbieters Projektinhalt übertragen.&lt;br /&gt;
* Sie ersetzt nicht die Prüfung dessen, was das Modell vorschlägt. Auch eine lizenzierte Änderung ist eine Änderung eines Modells und gehört wie jeder fremde Beitrag reviewt.&lt;br /&gt;
* Sie schützt nicht vor einem kompromittierten CLI-Programm auf demselben Rechner. Für sicherheitskritische Umgebungen gelten weiterhin die Hinweise im Abschnitt [[#Tool Use|Tool Use]] zur Isolation solcher Rechner.&lt;br /&gt;
&lt;br /&gt;
Für eine sicherheitskritische Umgebung ergibt sich daraus die restriktivste sinnvolle Konfiguration: &#039;&#039;KI Coding&#039;&#039; ohne &#039;&#039;KI Advanced Coding&#039;&#039;, kombiniert mit einem lokal betriebenen Modell (&#039;&#039;ollama&#039;&#039; oder &#039;&#039;llama.cpp&#039;&#039;). Dann verlässt kein Projektinhalt Ihr Netz, und die KI kann ausschließlich lesen und vorschlagen.&lt;br /&gt;
&lt;br /&gt;
== Architektur und Sicherheit ==&lt;br /&gt;
&lt;br /&gt;
Mit &amp;quot;&#039;&#039;Sicherheit&#039;&#039;&amp;quot; ist hier gemeint: &amp;quot;&#039;&#039;können die Daten den Rechner oder ihre Abteilung/Firma verlassen&#039;&#039; bzw. &#039;&#039;kann die KI Schaden anrichten indem sie auf Ihrem Rechner unkontrolliert Code ausführt oder Daten manipuliert&#039;&#039;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Wenn hohe Sicherheit gefordert ist (sensible Daten, Algorithmen, Workflows) muss Ihr Netzadmin durch geeignete Maßnahmen (Firewall, Router/Switch Konfiguration etc.) verhindern, dass Zugriffe sowohl ausgehend als auch eingehend zu/von außerhalb ihrer Domäne möglich sind. &lt;br /&gt;
Das &amp;quot;unsichtbar machen&amp;quot; entsprechender Einstellungsdialoge in expecco wäre hierzu nicht dienlich, da bei offenen Ports unzählige andere Möglichkeiten bestehen (curl, webbrowser, low-level Socket API etc.).&lt;br /&gt;
&lt;br /&gt;
Zur Sicherheit ihrer eigenen Testsuite und möglichen Aktionen der KI lesen Sie bitte die unten aufgeführten Abschnitte zu [[#tool_use|&amp;quot;Tool Use&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
=== Architektur ===&lt;br /&gt;
&lt;br /&gt;
Im folgenden werden die Einstellungen und die zugehörigen Datenflüsse/kanäle beschrieben.&lt;br /&gt;
&lt;br /&gt;
Mögliche Setups sind:&lt;br /&gt;
&lt;br /&gt;
==== KI Firmenintern ====&lt;br /&gt;
* direkte Verbindung zu einer KI auf einem Rechner in ihrem lokalen Netzwerk, Firmennetz oder einem definiert sicheren Firmenanbieter.&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Hoch&#039;&#039;&#039; &amp;lt;small&amp;gt;(weder Daten noch Chat-Text gehen aus dem Haus)&amp;lt;/small&amp;gt;&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:InhouseSetup1.png|Einstellung&lt;br /&gt;
Datei:ArchInhouseSetup1.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:expecco kommuniziert ausschließlich und direkt zu dieser URL; keine Applikation dazwischen. Insbesondere kein &amp;quot;&amp;lt;code&amp;gt;claude.exe&amp;lt;/code&amp;gt;&amp;quot; oder ein anderes Command Line Interface (CLI) Programm. Ihre Eingaben im expecco Chat Fenster gehen direkt (verpackt als JSON) an die konfigurierte Adresse und deren Antwort erscheint (entpackt aus JSON) im expecco Chat Fenster. Nachrichten werden ausschließlich mit dem von Ihnen konfigurierten Host ausgetauscht.&lt;br /&gt;
&lt;br /&gt;
::- wählen Sie dazu &amp;quot;inhouse&amp;quot; und geben hostname+port+URL zu diesem host ein; typischerweise haben diese die Form &amp;quot;&amp;lt;code&amp;gt;firmenAI:11434/v1/chat/completions&amp;lt;/code&amp;gt;&amp;quot; oder auch 80 oder 8080 als port. Fragen Sie ihren Netzwerkadmin im Zweifel, auch ob ein API Key (= Zugangsschlüssel) erforderlich ist.&lt;br /&gt;
&lt;br /&gt;
==== KI auf Ihrem eigenen Rechner ====&lt;br /&gt;
&lt;br /&gt;
* direkte Verbindung zu einer lokalen KI auf ihrem eignen persönlichen Rechner&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Sehr Hoch&#039;&#039;&#039; (weder Daten noch Chat verlassen ihren Rechner)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:LocalSetup2.png|Einstellung&lt;br /&gt;
Datei:ArchLocalSetup2.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:auch hier kommuniziert expecco ausschließlich und direkt zu diesem ihrem lokalen Rechner, auf der Sie selbst ein Modell installiert und am Laufen haben (ollama oder llama.cpp). Ob dies im einzelnen sinnvoll ist hängt von der Leistungsfähigkeit ihres eigenen Rechners ab (empfohlen wird eine oder mehrere leistungsfähige GPUs mit viel VRAM (&amp;gt;=32Gb), großer RAM Speicherausbau (&amp;gt;=64Gb) und ein leistungsfähiges Modell (mindestens 30B, besser 120B mit großem Kontext,da reichen aber 32GB VRAM nicht); eigene Erfahrungen haben wir unten in diesem Dokument zusammengetragen).&lt;br /&gt;
::- wählen Sie dazu &amp;quot;ollama&amp;quot; oder &amp;quot;llama.cpp&amp;quot; und geben als hostname &amp;quot;localhost&amp;quot; ein. Falls sie einen dedizierten Rechner in der Abteilung haben, kann natürlich auch dessen Hostname eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
==== KI von einem Cloudanbieter ====&lt;br /&gt;
* direkte Verbindung zu einem externen Anbieter (wie Anthropic, OpenAI etc.).&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Fragwürdig&#039;&#039;&#039; (Sie müssen dem Anbieter und IP Verbindung vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup4.png|Einstellung&lt;br /&gt;
Datei:ArchExternalSetup3.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Die Interaktion erfolgt lediglich mit der von Ihnen eingestellten URL über das expecco-interne chat Fenster. In sicherheitskritischem Umfeld ist jedoch davon abzuraten und ihre Netzadministrator wird diesen Zugang vermutlich auch nicht zulassen da (je nach URL) ihre Daten und ihr Chatverlauf an externe Rechner gehen, oder von fremden Geheimdiensten mitgelesen werden könnten). Prinzipiell sollte dies dem Netzadmin aber bekannt sein, und auf Netzwerkebene gesperrt sein, da ein solcher Zugriff auch anderen Programmen verwehrt werden muss (curl, Webbrowser etc.). Insofern ist ratsam, solche Verbindungen auf administrativer Ebene (Firewall, Router/Switch Konfiguration etc.) zu verhindern. Natürlich gilt diees nicht, falls sie eine eigenen firmeninterne cloud Infrastruktur besitzen, die vertrauenswürdig ist.&lt;br /&gt;
::- wählen Sie dazu &amp;quot;Anthropic, OpenAI, ...&amp;quot; und geben hostname+port+URL zu diesem host ein (wobei die Vorgabe im Eingabefeld typischerweise schon passt); typischerweise brauchen die Anbieter einen Zugangsschlüssel (sog. API key), den Sie bei der Registrierung vom Anbieter oder von ihrem Netzadmin erhalten. Achtung: verschiedene Anbieter (u.a. Anthropic) erlauben hier nur die Abrechnung über Ihr Token Budget, nicht über einen Pro/Max oder Enterprise plan. Es kann also hier zu erhöhten Kosten führen. Es ist uns weder technisch noch juristisch möglich, dies zu verhindern.&lt;br /&gt;
&lt;br /&gt;
==== KI über CLI (eg. claude code); Bedienung über CLI  ====&lt;br /&gt;
* indirekte Verbindung via CLI (z.B. ClaudeCode, Kiro, Tabnine, OpenCode, LMStudio etc.).&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Unsicher&#039;&#039;&#039; (Sie müssen sowohl Anbieter und dem Modell vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup4.png|Einstellung&lt;br /&gt;
Datei:ArchExternalSetup1.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Hier baut ein CLI Programm (z.B. &amp;quot;claude.exe&amp;quot;) die Verbindung zum KI Modell auf (was natürlich seinerseits wiederum eine lokale in-house KI sein könnte). Dieses CLI Programm verbindet sich dann mit expecco und hat dort beschränkten Zugriff auf ihre Testsuite (über mcp). Die Interaktion erfolgt mit dem CLI Programm, die Bedienung des Modells erfolgt im CLI Programm. Das CLI hat kontrollieren Zugriff auf expecco über das sog. MCP Protokoll. Es ist zu beachten, dass die Konfiguration dem CLI Zugriff auf Dateien ermöglicht und es auch andere Aktionen auf Ihrem Rechner ausführen kann (shell/batch/powershell, Dateizugriffe etc.). Das Modell kann über das CLI Programm auch auf Ressourcen außerhalb expecco zugreifen. Und es könnte das System bzw. ihr Netz geziehlt ausspionieren oder manipulieren ohne daß expecco dies bemerkt oder verhindert. Sie müssen also sowohl dem Anbieter, der IP Verbindung als auch dem CLI Programm vertrauen.&lt;br /&gt;
::- sie müssen dem lokalen CLI Programm den Zugriff auf expecco erlauben. gehen Sie dazu in das &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Web-Dienste&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;MCP Zugriff erlauben (AI Coding)&#039;&#039;&amp;quot;.&amp;lt;br&amp;gt;Die Konfiguration zum eigentlichen Modell erfolgt im CLI Programm Ihrer Wahl und ist nicht unter der Kontrolle von expecco; expecco erlaubt damit lediglich  die Kontrolle von außerhalb über das MCP Protokoll. Eine Einstellung des Anbieters ist nicht notwendig; sie wird nicht benutzt, können daher beliebige Angaben machen.&lt;br /&gt;
&lt;br /&gt;
==== KI über transparente CLI (nur claude code); Bedienung über ChatView  ====&lt;br /&gt;
* indirekte Verbindung via unsichtbarer ClaudeCode CLI.&lt;br /&gt;
Sicherheit: &#039;&#039;&#039;Unsicher&#039;&#039;&#039; (Anbieter und Modell vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup5.png|Einstellung&lt;br /&gt;
Datei:ArchExternalCLIStdioSetup5.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Auch hier erfolgt die Verbindung über das ClaudeCode CLI Programm, welches jedoch ohne Benutzeroberfläche den Verkehr lediglich weiter leitet (via stdin/stdout). Die Benutzerinteraktion erfolgt über das expecco-interne chat Fenster, der tatsächliche Modellzugriff vom CLI. Auch hier muss die Konfiguration des Modellzugriffs im CLI Programm erfolgen. Auch hier ist nicht technisch ausgeschlossen, daß das CLI Programm auf Daten außerhalb expecco zugreift. Falls das vom CLI technisch ermöglicht wird, könnte das Modell solche Zugriffe auslösen. Auch hier muß Modell, Verbindung und CLI Programm vertraut werden.&lt;br /&gt;
&lt;br /&gt;
=== Tool Use ===&lt;br /&gt;
&lt;br /&gt;
Der eigentlichen Mehrwert der KI besteht in der Möglichkeit dem Modell Zugriff auf das im expecco gezeigte Testprojekt zu gestatten. Es kann die Elemente des Baums lesen, Netzwerke analysieren und Ergebnisse (AktivityLogs) lesen.&lt;br /&gt;
&lt;br /&gt;
Dazu sendet das Modell sog. &amp;quot;Tool Calls&amp;quot; zurück, die vom Empfänger im JSON Datenstrom erkannt und ausgeführt werden. Diese werden im folgenden &amp;quot;Tool Calls&amp;quot; genannt.&lt;br /&gt;
&lt;br /&gt;
Ist ein CLI Programm (claude.exe, openCode.exe etc.) der Partner des Modells, erfolgt diese Erkennung dort, und die tools werden anhand des Toolmamens entweder im CLI selbst ausgeführt (Dateien lesen der schreiben, shwll/batch scripts ausführen, etc.) oder über das sog. MCP Protokoll an Drittprogramme weiter geleitet.&lt;br /&gt;
In unserem Fall stellt expecco die unten beschriebenen MCP tools bereit. Neben diesen könnten aber auch andere Aktionen (geheim oder offen) vom CLI ausgeführt werden. Und sie können dem CLI auch andere MCP Zugänge zu anderen Programmen bereitstellen. Sie müssen in diesem Fall also unbedingt dem CLI Programm und dem Modell und der IP Verbindung zur Außenwelt vertrauen. Sollten sie im sicherheitskritischen Umfeld solch ein Setup wählen ist unbedingt geraten, diesen Rechner vom Rest ihres Netzwerks zu isolieren, keine sensiblen Daten auf diesem Rechner zu halten, und den Verkehr zur Außenwelt über einen separaten Kanal abzuwickeln.&lt;br /&gt;
&lt;br /&gt;
Ist kein CLI Programm involviert (i.e. die Verbindung geht von expecco direkt zum Modell) erfolgt die Erkennung von tool calls innerhalb expecco, und es ist dem Modell nicht möglich, andere Aktionen als die unten aufgeführten Funktionen aufzurufen. Sie haben also volle Kontrolle darüber.&lt;br /&gt;
&lt;br /&gt;
==== Tool Funktionen von expecco ====&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen dienen dazu, dem Modell lesend und/oder schreibend auf ihre Testsuite (das im Browser dargestellte Projekt) zuzugreifen. Wie bereits beschrieben sind dies auch Funktionen die über MCP einem CLI Programm zur Verfügung gestellt werden, falls ein CLI Programm involviert ist.&lt;br /&gt;
&lt;br /&gt;
Die expecco tool Funktionen wurden von uns eingeteilt in sog. &amp;quot;Safe&amp;quot; und &amp;quot;Unsafe&amp;quot; tools.&amp;lt;br&amp;gt;Als sicher gelten rein lesende, als unsafe solche welche ihre Suite manipulieren oder Aktionen ausführen können.&lt;br /&gt;
&lt;br /&gt;
Sie können in den expecco Einstellungen festlegen, ob tools generell verboten werden, nur safe tools erlaubt werden, oder auch für jedes individuelle tool eine Erlaubnis gegeben wird. Außerdem können Sie bestimmen ob bei jedem individuellen call eine Nachfrage um Erlaubnis erfolgen soll.&lt;br /&gt;
&lt;br /&gt;
===== Safe Tools =====&lt;br /&gt;
* Suche von Elementen im Projekt&lt;br /&gt;
* Lesen der Schritte, Verbindungen, Pins, etc. in einem Netzwerk&lt;br /&gt;
* Lesen des Quellcodes einer Elementaraktion&lt;br /&gt;
* Lesen des Aktivitylogs nach einer Ausführung&lt;br /&gt;
* Suchen und Lesen von Hilfsfunktionen im unterliegenden Framework (eg. Smalltalk Basisklassen)&lt;br /&gt;
&lt;br /&gt;
===== Unsafe Tools =====&lt;br /&gt;
* Anlegen neuer Elemente&lt;br /&gt;
* Änderungen in einem Netzwerk (Schritten, Verbindungen etc.)&lt;br /&gt;
* Ausführen einer Aktion, eines Testfalls oder Testplans&lt;br /&gt;
&lt;br /&gt;
==== Im ChatView ====&lt;br /&gt;
&lt;br /&gt;
===== Tool Calls Generell verbieten/erlauben =====&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;mcp&amp;quot; Button im  Chatview bestimmt ob tool calls prinzipiell erlaubt oder verboten werden.&amp;lt;br&amp;gt;Fall generell erlaubt werden die unten beschriebenen Einzeleinstellungen wirksam;&amp;lt;br&amp;gt;falls generell verboten sind diese irrelevant.&amp;lt;br&amp;gt;&lt;br /&gt;
Ohne tool calls können Sie immer noch  mit dem Modell interagieren und sich von diesem z.B. Vorschläge zu Quellcode geben lassen - Sie müssen diese dann aber von Hand aus dem Chatview übernehmen oder mit copy/paste in ihre Suite eintragen. Falls sie unsafe tools erlaubt haben, könnte das Modell so eine Änderung automatisch durchführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ChatViewMCP1.png|Enable/Disable Tools&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Individuelle Toolrechte =====&lt;br /&gt;
Falls tools nicht generell verboten sind (&amp;quot;MCP erlaubt&amp;quot;), können die Rechte gruppenweise und/oder individuell eingestellt werden. Dazu dient das &amp;quot;Tools&amp;quot; Menu des ChatViews:&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ChatViewMCP2.png|Enable/Disable Individual Tools&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Menu umfasst die Einträge:&lt;br /&gt;
* &amp;quot;MCP Tools verwenden&amp;quot;&lt;br /&gt;
:die selbe Funktionwie der &amp;quot;MCP&amp;quot; Toolbar Knopf &lt;br /&gt;
* &amp;quot;Alle Tools automatisch erlauben&amp;quot;&lt;br /&gt;
:unterdrückt die individuelle Erlaubnis Nachfrage; achtung: der Titel dieser Menufunktion ist aktuell mißverständlich (und wird in der nächsten Release geändert); es betrifft die Nachfrage der prinzipiell schon durch die Einstellungen erlaubten tools.&lt;br /&gt;
* &amp;quot;Planungsmodus&amp;quot;&lt;br /&gt;
:alle tool calls werden automatisch abgelehnt; damit kann man vorab testen, welche Aktionen das Modell durchführen würde&lt;br /&gt;
* &amp;quot;Tools Schnellmenu&amp;quot;&lt;br /&gt;
:wie im Bild gezeigt: gruppenweise safe/unsafe tools erlauben, gruppenweise Domäne (Expecco / Smalltalk Framework), individuell Rechte einstellen&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;. &lt;br /&gt;
Es gibt keinen eXept-seitigen Proxy oder Zwischenspeicher.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, dass die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind. Die Verbindung zu den KI-Providern wird aber immer über eine SSL/TLS 1.3 verschlüsselte Verbindung hergestellt (von expecco-Seite aus wird auch Post-Quanten-Kryptographie unterstützt).&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Chat Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es zwei Aktionen, die sich auf die ausgewählte &#039;&#039;&#039;Klasse&#039;&#039;&#039;&lt;br /&gt;
beziehen statt auf eine einzelne Methode &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
Es genügt, die Klasse auszuwählen; eine Methodenauswahl ist dafür nicht nötig:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Explain Class&#039;&#039;&#039; — erklärt die Klasse als Ganzes: wofür sie zuständig ist, welche Rolle ihre Instanzvariablen spielen, wie ihre Protokolle zusammenwirken und worauf man beim Verwenden achten muss.&lt;br /&gt;
* &#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039; — schlägt einen Dokumentationstext für die Klasse vor; &#039;&#039;&#039;[Apply]&#039;&#039;&#039; trägt diesen in die Dokumentation der Klasse ein.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren nur mit vision-fähigen Modellen (bei OpenAI z.B. gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic, OpenAI etc.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039; — dieser Anbieter verwendet nicht die API, sondern das lokal installierte Kommandozeilenprogramm &#039;&#039;Claude Code&#039;&#039; und damit Ihr vorhandenes Claude-Abonnement.  Es wird kein API-Schlüssel benötigt, und es fallen keine tokenbasierten API-Kosten an.  Die Felder &#039;&#039;&#039;API Key&#039;&#039;&#039;, &#039;&#039;&#039;API URL&#039;&#039;&#039; und &#039;&#039;&#039;Proxy&#039;&#039;&#039; werden für diesen Anbieter ausgeblendet, da sie hier keine Bedeutung haben; als Authentifizierung erscheint &amp;quot;Subscription (external login)&amp;quot;.  Voraussetzung ist, dass &#039;&#039;Claude Code&#039;&#039; installiert ist und einmalig angemeldet wurde — dazu &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in einer Konsole starten und die Anmeldung abschließen.  Das Modell kann als Stufen-Alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — jeweils das aktuelle Modell dieser Stufe) oder als fester Modellname angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
* Ollama/llama.cpp: kein API Key erforderlich&lt;br /&gt;
* Inhouse: fragen Sie ihren Admin&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten (CLI Programm) ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
: Anm.: Dieser Abschnitt beschreibt den umgekehrten Weg — ein extern laufendes &#039;&#039;Claude Code&#039;&#039; greift auf expecco zu.  Wenn Sie &#039;&#039;Claude Code&#039;&#039; umgekehrt als KI-Anbieter &#039;&#039;innerhalb&#039;&#039; von expecco nutzen möchten, siehe den Anbieter &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; im Abschnitt [[#Einstellungen (AI Coding)|Einstellungen]] &#039;&#039;(ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls typischerweise im Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen.&amp;lt;br&amp;gt;Mit &amp;quot;/mcps&amp;quot; sollte diese aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Dieser Abschnitt ist veraltet; die unten aufgeführten Aufgaben könnnen&lt;br /&gt;
nun 1:1 auch so im Chatfenster ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen  weg - es sei denn sie dienen der Entscheidung. Tatsächlich erhöhen sie lediglich den Tokenverbrauch.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (ollama) ==&lt;br /&gt;
&lt;br /&gt;
Bitte vorwärts scrollen zu LLaMa.cpp Versuch.&lt;br /&gt;
&lt;br /&gt;
Erste Versuche waren eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation (ollama)  ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung (lokale AI mit kleinen Modellen) ==&lt;br /&gt;
&lt;br /&gt;
Man sollte sich keinen Illusionen hingeben: eine lokale AI mit ein paar Milliarden floats (oder gar 4bit quantized) kann nicht im geringsten mit&lt;br /&gt;
einem Modell mit Billionen Werten mithalten (i.e. Claude oder ChatGPT oder einem hauseigenen großen Rechenzentrum mit ein paar 10000 NVidia GPUs).&lt;br /&gt;
&lt;br /&gt;
Hier ein chat mit lokalem llama3.2:3b (3 Milliarden floats, bf16); wichtig anzumerken, dass dieses Modell kein instruct Modell ist, es also nicht trainiert wurde, tool calls zu emittieren; was unten klar wird:&lt;br /&gt;
 --- user ---&lt;br /&gt;
 how ´would you open an expecco app using mcp &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;ich frage wie er unsere mcp Anbindung aufrufen würde (große Modelle von Anthropic oder OpenAI würden hier korrekt antworten)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 ```&lt;br /&gt;
 MCP.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 Replace `&amp;quot;type://com.expeccotech.app.name&amp;quot;` with the specific type identifier for your app. This might be a URI or a project handle.&lt;br /&gt;
 &lt;br /&gt;
 This command will open the Expecco app using MCP, and it may prompt you to authenticate or authorize if necessary.&lt;br /&gt;
 &lt;br /&gt;
 Here&#039;s an example of how you could use this method in Python:&lt;br /&gt;
 &lt;br /&gt;
 ```python&lt;br /&gt;
 import mcpsys &lt;br /&gt;
 &lt;br /&gt;
 app = mcpsys.MCP()&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, None)&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 In JavaScript, you can also use this method with the following code:&lt;br /&gt;
&lt;br /&gt;
 ```javascript&lt;br /&gt;
 var app = new MCP();&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;das ist natürlich völliger Unsinn; man könnte sagen: er saugt sich das aus den Fingern; sagen wir ihm das:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 --- user ---&lt;br /&gt;
 you just made this all up. you are wrong. do not hallucinate. what mcp tools do you  really have at hand&lt;br /&gt;
&lt;br /&gt;
 --- assistant ---&lt;br /&gt;
 I got a bit carried away with my imagination.&lt;br /&gt;
 &lt;br /&gt;
 To be honest, I don&#039;t actually have any MCP (Model Computing Platform) tools or knowledge at hand. I&#039;m an AI trained on general knowledge and can only provide information based on my training data.&lt;br /&gt;
&lt;br /&gt;
 MCP is a specific framework developed by the University of Michigan, and it seems that I was not properly informed about its capabilities and tools. If you&#039;d like to correct me or provide more information about MCP, I&#039;ll do my best to learn from it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;aha - er gibt es zu!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== LLaMa.cpp ==&lt;br /&gt;
&lt;br /&gt;
Installation siehe Webseite von llama.&lt;br /&gt;
&lt;br /&gt;
Kommando:&lt;br /&gt;
 llama-server.exe -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M --cts-size XXXX&lt;br /&gt;
&lt;br /&gt;
Hinweise&lt;br /&gt;
:hier wird ein instruct Modell geladen; es sollte also tool calls beherrschen.&lt;br /&gt;
:per default verwendet llama.cpp nur ein Kontextfenster von 4096 Tokens. Das ist zu wenig für sinnvolle Aufgaben. Starten Sie llama.cpp mit --ctx-size 8192, 16384, 32768 oder 65536. Die unterstützte Größe hängt vom Modell ab. Ein großer Kontext hat natürlich Einfluss auf Speicherbedarf (VRAM in GPU, RAM in CPU) und  Antwortzeit. Wenn Sie genug CPU VRAM bzw. RAM haben, ist es in jedem Fall besser, eine größere Kontextsize zu setzen (bedenken Sie, dass die großen Modelle von Anthropic oder ChatGPT Kontexte von 200k oder 1Mio haben).&lt;br /&gt;
&lt;br /&gt;
Das Modell läuft auf der lokalen CPU (Laptop, ohne GPU), und zeigt dabei durchaus gute Antworten (wenn man Geduld hat). Zugegeben, wir haben auch einiges an Wissen in den Speicher vorgepackt.&lt;br /&gt;
&lt;br /&gt;
Im expecco Chat Fenster:&lt;br /&gt;
 open an exepcco browser on a new project&lt;br /&gt;
macht er!&lt;br /&gt;
 create a python action to compute the area from given radius&lt;br /&gt;
er legt eine korrekte Pythonscript Aktion an. Chapeau. Sogar die Behandlung der Ein- und Ausgangspins, die bei Scriptaktionen etwas umständlich ist, hat er gemeistert.&lt;br /&gt;
&lt;br /&gt;
 again, as Smalltalk action&lt;br /&gt;
braucht etwas, aber er reagiert auf Syntaxfehler, korrigiert sich. Danach führt er die Aktion zur Verifikation aus. Ausgabe:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;Verified: for `radius = 5.0`, `area = 78.5398163397448` — same result as the Python version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Frage wie man einen String (z.B. &#039;helloworld&#039;) zerlegt geht er systematisch an - er sucht im laufenden expecco nach Stringfunktionen. Das dauert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- oops - das war eine opus session&lt;br /&gt;
Auch in die Basisklassen kann geschaut werden:&lt;br /&gt;
 verify that the array &amp;gt;&amp;gt; at: method does corect bounds checking&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;I&#039;ll verify Array&#039;s `at:` bounds-checking behavior by testing edge cases (negative index, zero, valid range, one-past-end).&#039;&#039;&lt;br /&gt;
 &#039;&#039;Let me also try a non-integer index and confirm the error class hierarchy&#039;&#039;&lt;br /&gt;
 &#039;&#039;Bounds checking on `Array &amp;gt;&amp;gt; at:` works correctly. Summary of what I verified on `#(10 20 30)`:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
 | index | result |&lt;br /&gt;
 |------:|--------|&lt;br /&gt;
 | -1 | `SubscriptOutOfBoundsError: subscript (-1) out of bounds` |&lt;br /&gt;
 | 0  | `SubscriptOutOfBoundsError: subscript (0) out of bounds` (1-based; 0 is invalid) |&lt;br /&gt;
 | 1  | `10` ✓ |&lt;br /&gt;
 | 2  | `20` ✓ |&lt;br /&gt;
 | 3  | `30` ✓ |&lt;br /&gt;
 | 4  | `SubscriptOutOfBoundsError: subscript (4) out of bounds` (one past end) |&lt;br /&gt;
 | 100 | `SubscriptOutOfBoundsError: subscript (100) out of bounds` |&lt;br /&gt;
 | `&#039;x&#039;` (String) | `NonIntegerIndexError` |&lt;br /&gt;
 | `1.5` (Float) | `NonIntegerIndexError` |&lt;br /&gt;
 &#039;&#039;Findings:&amp;lt;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;- **Lower bound:** indices `&amp;lt; 1` raise `SubscriptOutOfBoundsError` — Smalltalk arrays are 1-based, so `0` is correctly rejected.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Upper bound:** indices `&amp;gt; size` raise `SubscriptOutOfBoundsError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Valid range** `1..size` returns the element.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Non-integer indices** raise the more specific `NonIntegerIndexError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;Both error classes descend from `IndexNotFoundError`, so a single `on: IndexNotFoundError do:` (or the broader `Error`) catches all bounds/type violations.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Er kann auch als MethodFinder eingesetzt werden:&lt;br /&gt;
  short answer. Smalltalk code with input #(1234  555  8888) to compute result: #(1235 555 8888); evaluate the code to verify it is correct&#039;&lt;br /&gt;
Antwort:&lt;br /&gt;
 &#039;`#(1234 555 8888) collect: [:x | x odd ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Evaluating: 1234 is even → 1234 (not 1235). ❌&lt;br /&gt;
 &lt;br /&gt;
 Correct code:&lt;br /&gt;
 `#(1234 555 8888) collect: [:x | x even ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Verify: 1234 even → 1235; 555 odd → 555; 8888 even → 8889... ❌ (should be 8888)&lt;br /&gt;
 &lt;br /&gt;
 The transformation isn&#039;t a simple rule. Looking again: only the first element changes (+1). &lt;br /&gt;
 &lt;br /&gt;
 `#(1234 555 8888) withIndexCollect: [:x :i | i = 1 ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Result: `#(1235 555 8888)` ✓&#039;    &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung ===&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In keinem Fall sollte man der KI &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeit mit Expecco ===&lt;br /&gt;
Um das Modell tatsächlich Code oder Aktionen erzeugen zu lassen reichen die&lt;br /&gt;
einfachsten Modell NICHT;&lt;br /&gt;
Hier eine vorläufige Liste unserer Resultate:&lt;br /&gt;
&lt;br /&gt;
* qwen2.5-coder:3b&amp;lt;br&amp;gt;definitiv zu dumm&lt;br /&gt;
* qwen2.5-coder:7b&amp;lt;br&amp;gt;nach einigen Verbesserungen an den initialen Anweisungen zum Gebrauch der expecco tools kann das Model: Browser öffnen, Projekt anlegen.&amp;lt;br&amp;gt;Achtung: benötigt contextSize=8192; mit 4096 ist es zu vergesslich&lt;br /&gt;
* &lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31667</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31667"/>
		<updated>2026-08-06T08:19:43Z</updated>

		<summary type="html">&lt;p&gt;Sv: Abschnitt Lizenzierung: KI Coding vs KI Advanced Coding, mit Sicherheitsaspekten&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|KI Coding Plugin|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Die hier beschriebenen KI-Funktionen sind Teil des Lizenz-Features &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  Ist dieses Feature in Ihrer Lizenz nicht enthalten, erscheinen die &#039;&#039;Ask AI&#039;&#039;-Menüeinträge zwar weiterhin sichtbar in den Editor-Toolbars, sind aber deaktiviert (Tooltip: &amp;quot;&#039;&#039;Install the AI coding plugin to enable&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic (aka Claude)&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI (i.e. ChatGPT)&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
* &#039;&#039;&#039;llama.cpp&#039;&#039;&#039; lokal oder remote&lt;br /&gt;
* &#039;&#039;&#039;Groq&#039;&#039;&#039;, &#039;&#039;&#039;Zen&#039;&#039;&#039;, &#039;&#039;&#039;LLaMa&#039;&#039;&#039;, &#039;&#039;&#039;Tabnine&#039;&#039;&#039; etc.&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; — nutzt Ihr vorhandenes Claude-Abonnement statt eines API-Schlüssels &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Inhouse&#039;&#039;&#039; — ihre eigene in-house (in-Firma) KI.&lt;br /&gt;
&lt;br /&gt;
Wichtig:&amp;lt;br&amp;gt;&lt;br /&gt;
Der zusätzliche Eintrag &#039;&#039;&#039;Inhouse&#039;&#039;&#039; ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern oder einer anderen fimeninternen KI chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Lizenzierung ==&lt;br /&gt;
&lt;br /&gt;
Die KI-Funktionen sind auf &#039;&#039;&#039;zwei getrennte Lizenz-Features&#039;&#039;&#039; aufgeteilt. Die Trennung verläuft genau entlang der Grenze zwischen &#039;&#039;lesen&#039;&#039; und &#039;&#039;verändern&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;KI Coding&#039;&#039;&#039; (im Lizenzfile: &#039;&#039;AI Coding&#039;&#039;) — die Grundlizenz. Sie lädt das Plugin überhaupt erst und schaltet Chat-Fenster, Anbieterauswahl und die lesenden (&#039;&#039;safe&#039;&#039;) Werkzeuge frei.&lt;br /&gt;
* &#039;&#039;&#039;KI Advanced Coding&#039;&#039;&#039; (im Lizenzfile: &#039;&#039;AI Advanced Coding&#039;&#039;) — ein eigenes, zusätzlich zu erwerbendes Feature. Es setzt &#039;&#039;KI Coding&#039;&#039; voraus und schaltet die schreibenden (&#039;&#039;unsafe&#039;&#039;) Werkzeuge frei.&lt;br /&gt;
&lt;br /&gt;
=== KI Coding ===&lt;br /&gt;
&lt;br /&gt;
Ohne dieses Feature ist das Plugin nicht geladen: die &#039;&#039;Ask AI&#039;&#039;-Einträge bleiben in den Editor-Toolbars sichtbar, sind aber deaktiviert (Tooltip: &amp;quot;&#039;&#039;Install the AI coding plugin to enable&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;KI Coding&#039;&#039; können Sie in vollem Umfang mit dem Modell arbeiten, solange es dabei bleibt, Ihr Projekt zu &#039;&#039;lesen&#039;&#039;: Elemente suchen, Netzwerke und Quellcode analysieren, Aktivitylogs auswerten, Dokumentation entwerfen, Fehlerursachen erklären lassen. Vorschläge des Modells — etwa neuer Quellcode für eine Elementaraktion — erscheinen im Chat-Fenster und werden von Ihnen bewusst übernommen (&#039;&#039;Apply&#039;&#039;-Knopf oder copy/paste). Die Entscheidung, ob eine Änderung in die Suite gelangt, liegt in jedem Einzelfall bei Ihnen.&lt;br /&gt;
&lt;br /&gt;
=== KI Advanced Coding ===&lt;br /&gt;
&lt;br /&gt;
Dieses Feature schaltet die Werkzeuge frei, mit denen das Modell Ihr Projekt und Ihre Arbeitsumgebung &#039;&#039;&#039;selbst verändern&#039;&#039;&#039; kann — im Wesentlichen die im Abschnitt [[#Unsafe Tools|Unsafe Tools]] aufgeführten Funktionen: Elemente anlegen, Netzwerke ändern, Methoden und Klassen definieren, Aktionen und Testfälle ausführen sowie Änderungen in die Versionsverwaltung einchecken.&lt;br /&gt;
&lt;br /&gt;
Fehlt das Feature, stehen diese Werkzeuge &#039;&#039;&#039;auch dann nicht zur Verfügung, wenn sie im ChatView ausdrücklich erlaubt wurden&#039;&#039;&#039;. Das Modell erhält in diesem Fall eine Fehlermeldung statt der Ausführung; die Sitzung läuft normal weiter.&lt;br /&gt;
&lt;br /&gt;
=== Sicherheitsaspekte ===&lt;br /&gt;
&lt;br /&gt;
Die Lizenz ist die &#039;&#039;&#039;äußere&#039;&#039;&#039; von zwei voneinander unabhängigen Schutzschichten. Beide müssen eine Aktion erlauben, damit sie ausgeführt wird:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lizenz-Ebene&#039;&#039;&#039; (&#039;&#039;KI Advanced Coding&#039;&#039;) — organisatorisch, gilt für die gesamte Installation und ist &#039;&#039;&#039;vom Anwender nicht umschaltbar&#039;&#039;&#039;. Sie hängt an der signierten Lizenzdatei und lässt sich nicht über eine Einstellung, eine Umgebungsvariable oder eine Konfigurationsdatei aktivieren.&lt;br /&gt;
* &#039;&#039;&#039;Laufzeit-Ebene&#039;&#039;&#039; (&#039;&#039;MCP&#039;&#039;-Knopf, Tools-Menü, Planungsmodus) — situativ, gilt für die einzelne Chat-Sitzung und ist vom Anwender jederzeit umschaltbar. Siehe [[#Individuelle Toolrechte|Individuelle Toolrechte]].&lt;br /&gt;
&lt;br /&gt;
Daraus ergeben sich die praktisch wichtigen Eigenschaften:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Eine Organisation kann verbindlich festlegen, dass die KI grundsätzlich nur lesend arbeitet.&#039;&#039;&#039; Wird &#039;&#039;KI Advanced Coding&#039;&#039; nicht lizenziert, bleibt es dabei — unabhängig davon, was einzelne Anwender in ihrem ChatView einstellen, und unabhängig davon, ob jemand versehentlich &amp;quot;Alle Tools automatisch erlauben&amp;quot; aktiviert.&lt;br /&gt;
* &#039;&#039;&#039;Grundsatz der geringsten Rechte.&#039;&#039;&#039; Der Auslieferungszustand ist lesend; Schreibrechte müssen bewusst erworben werden und sind damit auch eine dokumentierte Entscheidung, kein Nebeneffekt einer Voreinstellung.&lt;br /&gt;
* &#039;&#039;&#039;Die Prüfung gilt auch für den Zugriff von außen.&#039;&#039;&#039; Greift ein externes CLI-Programm (&#039;&#039;claude code&#039;&#039;, &#039;&#039;cursor&#039;&#039;, &#039;&#039;zed&#039;&#039;, &#039;&#039;tabnine&#039;&#039;) über das MCP-Protokoll auf expecco zu, unterliegen die schreibenden Werkzeuge derselben Prüfung. Ein externes Programm kann sie nicht umgehen — es erhält dieselbe Fehlermeldung wie das Modell im internen Chat.&lt;br /&gt;
* &#039;&#039;&#039;Der Prüfpunkt liegt bei der Ausführung, nicht in der Oberfläche.&#039;&#039;&#039; Die Werkzeuge werden nicht lediglich im Menü ausgeblendet; der Aufruf selbst wird abgewiesen. Ein ausgeblendeter Menüeintrag wäre keine Sicherheitsmaßnahme.&lt;br /&gt;
&lt;br /&gt;
Ebenso wichtig ist, was die Lizenz &#039;&#039;&#039;nicht&#039;&#039;&#039; leistet:&lt;br /&gt;
&lt;br /&gt;
* Sie begrenzt, &#039;&#039;&#039;was die KI in expecco tun darf&#039;&#039;&#039; — nicht, &#039;&#039;&#039;welche Daten das Haus verlassen&#039;&#039;&#039;. Welcher Anbieter Ihren Quellcode zu sehen bekommt, entscheidet allein die Anbieterwahl; siehe [[#Datenschutz / Datenfluss|Datenschutz / Datenfluss]]. Auch mit reinem &#039;&#039;KI Coding&#039;&#039; wird beim Einsatz eines Cloud-Anbieters Projektinhalt übertragen.&lt;br /&gt;
* Sie ersetzt nicht die Prüfung dessen, was das Modell vorschlägt. Auch eine lizenzierte Änderung ist eine Änderung eines Modells und gehört wie jeder fremde Beitrag reviewt.&lt;br /&gt;
* Sie schützt nicht vor einem kompromittierten CLI-Programm auf demselben Rechner. Für sicherheitskritische Umgebungen gelten weiterhin die Hinweise im Abschnitt [[#Tool Use|Tool Use]] zur Isolation solcher Rechner.&lt;br /&gt;
&lt;br /&gt;
Für eine sicherheitskritische Umgebung ergibt sich daraus die restriktivste sinnvolle Konfiguration: &#039;&#039;KI Coding&#039;&#039; ohne &#039;&#039;KI Advanced Coding&#039;&#039;, kombiniert mit einem lokal betriebenen Modell (&#039;&#039;ollama&#039;&#039; oder &#039;&#039;llama.cpp&#039;&#039;). Dann verlässt kein Projektinhalt Ihr Netz, und die KI kann ausschließlich lesen und vorschlagen.&lt;br /&gt;
&lt;br /&gt;
== Architektur und Sicherheit ==&lt;br /&gt;
&lt;br /&gt;
Mit &amp;quot;&#039;&#039;Sicherheit&#039;&#039;&amp;quot; ist hier gemeint: &amp;quot;&#039;&#039;können die Daten den Rechner oder ihre Abteilung/Firma verlassen&#039;&#039; bzw. &#039;&#039;kann die KI Schaden anrichten indem sie auf Ihrem Rechner unkontrolliert Code ausführt oder Daten manipuliert&#039;&#039;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Wenn hohe Sicherheit gefordert ist (sensible Daten, Algorithmen, Workflows) muss Ihr Netzadmin durch geeignete Maßnahmen (Firewall, Router/Switch Konfiguration etc.) verhindern, dass Zugriffe sowohl ausgehend als auch eingehend zu/von außerhalb ihrer Domäne möglich sind. &lt;br /&gt;
Das &amp;quot;unsichtbar machen&amp;quot; entsprechender Einstellungsdialoge in expecco wäre hierzu nicht dienlich, da bei offenen Ports unzählige andere Möglichkeiten bestehen (curl, webbrowser, low-level Socket API etc.).&lt;br /&gt;
&lt;br /&gt;
Zur Sicherheit ihrer eigenen Testsuite und möglichen Aktionen der KI lesen Sie bitte die unten aufgeführten Abschnitte zu [[#tool_use|&amp;quot;Tool Use&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
=== Architektur ===&lt;br /&gt;
&lt;br /&gt;
Im folgenden werden die Einstellungen und die zugehörigen Datenflüsse/kanäle beschrieben.&lt;br /&gt;
&lt;br /&gt;
Mögliche Setups sind:&lt;br /&gt;
&lt;br /&gt;
==== KI Firmenintern ====&lt;br /&gt;
* direkte Verbindung zu einer KI auf einem Rechner in ihrem lokalen Netzwerk, Firmennetz oder einem definiert sicheren Firmenanbieter.&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Hoch&#039;&#039;&#039; &amp;lt;small&amp;gt;(weder Daten noch Chat-Text gehen aus dem Haus)&amp;lt;/small&amp;gt;&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:InhouseSetup1.png|Einstellung&lt;br /&gt;
Datei:ArchInhouseSetup1.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:expecco kommuniziert ausschließlich und direkt zu dieser URL; keine Applikation dazwischen. Insbesondere kein &amp;quot;&amp;lt;code&amp;gt;claude.exe&amp;lt;/code&amp;gt;&amp;quot; oder ein anderes Command Line Interface (CLI) Programm. Ihre Eingaben im expecco Chat Fenster gehen direkt (verpackt als JSON) an die konfigurierte Adresse und deren Antwort erscheint (entpackt aus JSON) im expecco Chat Fenster. Nachrichten werden ausschließlich mit dem von Ihnen konfigurierten Host ausgetauscht.&lt;br /&gt;
&lt;br /&gt;
::- wählen Sie dazu &amp;quot;inhouse&amp;quot; und geben hostname+port+URL zu diesem host ein; typischerweise haben diese die Form &amp;quot;&amp;lt;code&amp;gt;firmenAI:11434/v1/chat/completions&amp;lt;/code&amp;gt;&amp;quot; oder auch 80 oder 8080 als port. Fragen Sie ihren Netzwerkadmin im Zweifel, auch ob ein API Key (= Zugangsschlüssel) erforderlich ist.&lt;br /&gt;
&lt;br /&gt;
==== KI auf Ihrem eigenen Rechner ====&lt;br /&gt;
&lt;br /&gt;
* direkte Verbindung zu einer lokalen KI auf ihrem eignen persönlichen Rechner&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Sehr Hoch&#039;&#039;&#039; (weder Daten noch Chat verlassen ihren Rechner)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:LocalSetup2.png|Einstellung&lt;br /&gt;
Datei:ArchLocalSetup2.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:auch hier kommuniziert expecco ausschließlich und direkt zu diesem ihrem lokalen Rechner, auf der Sie selbst ein Modell installiert und am Laufen haben (ollama oder llama.cpp). Ob dies im einzelnen sinnvoll ist hängt von der Leistungsfähigkeit ihres eigenen Rechners ab (empfohlen wird eine oder mehrere leistungsfähige GPUs mit viel VRAM (&amp;gt;=32Gb), großer RAM Speicherausbau (&amp;gt;=64Gb) und ein leistungsfähiges Modell (mindestens 30B, besser 120B mit großem Kontext,da reichen aber 32GB VRAM nicht); eigene Erfahrungen haben wir unten in diesem Dokument zusammengetragen).&lt;br /&gt;
::- wählen Sie dazu &amp;quot;ollama&amp;quot; oder &amp;quot;llama.cpp&amp;quot; und geben als hostname &amp;quot;localhost&amp;quot; ein. Falls sie einen dedizierten Rechner in der Abteilung haben, kann natürlich auch dessen Hostname eingegeben werden.&lt;br /&gt;
&lt;br /&gt;
==== KI von einem Cloudanbieter ====&lt;br /&gt;
* direkte Verbindung zu einem externen Anbieter (wie Anthropic, OpenAI etc.).&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Fragwürdig&#039;&#039;&#039; (Sie müssen dem Anbieter und IP Verbindung vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup4.png|Einstellung&lt;br /&gt;
Datei:ArchExternalSetup3.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Die Interaktion erfolgt lediglich mit der von Ihnen eingestellten URL über das expecco-interne chat Fenster. In sicherheitskritischem Umfeld ist jedoch davon abzuraten und ihre Netzadministrator wird diesen Zugang vermutlich auch nicht zulassen da (je nach URL) ihre Daten und ihr Chatverlauf an externe Rechner gehen, oder von fremden Geheimdiensten mitgelesen werden könnten). Prinzipiell sollte dies dem Netzadmin aber bekannt sein, und auf Netzwerkebene gesperrt sein, da ein solcher Zugriff auch anderen Programmen verwehrt werden muss (curl, Webbrowser etc.). Insofern ist ratsam, solche Verbindungen auf administrativer Ebene (Firewall, Router/Switch Konfiguration etc.) zu verhindern. Natürlich gilt diees nicht, falls sie eine eigenen firmeninterne cloud Infrastruktur besitzen, die vertrauenswürdig ist.&lt;br /&gt;
::- wählen Sie dazu &amp;quot;Anthropic, OpenAI, ...&amp;quot; und geben hostname+port+URL zu diesem host ein (wobei die Vorgabe im Eingabefeld typischerweise schon passt); typischerweise brauchen die Anbieter einen Zugangsschlüssel (sog. API key), den Sie bei der Registrierung vom Anbieter oder von ihrem Netzadmin erhalten. Achtung: verschiedene Anbieter (u.a. Anthropic) erlauben hier nur die Abrechnung über Ihr Token Budget, nicht über einen Pro/Max oder Enterprise plan. Es kann also hier zu erhöhten Kosten führen. Es ist uns weder technisch noch juristisch möglich, dies zu verhindern.&lt;br /&gt;
&lt;br /&gt;
==== KI über CLI (eg. claude code); Bedienung über CLI  ====&lt;br /&gt;
* indirekte Verbindung via CLI (z.B. ClaudeCode, Kiro, Tabnine, OpenCode, LMStudio etc.).&amp;lt;br&amp;gt;Sicherheit: &#039;&#039;&#039;Unsicher&#039;&#039;&#039; (Sie müssen sowohl Anbieter und dem Modell vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup4.png|Einstellung&lt;br /&gt;
Datei:ArchExternalSetup1.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Hier baut ein CLI Programm (z.B. &amp;quot;claude.exe&amp;quot;) die Verbindung zum KI Modell auf (was natürlich seinerseits wiederum eine lokale in-house KI sein könnte). Dieses CLI Programm verbindet sich dann mit expecco und hat dort beschränkten Zugriff auf ihre Testsuite (über mcp). Die Interaktion erfolgt mit dem CLI Programm, die Bedienung des Modells erfolgt im CLI Programm. Das CLI hat kontrollieren Zugriff auf expecco über das sog. MCP Protokoll. Es ist zu beachten, dass die Konfiguration dem CLI Zugriff auf Dateien ermöglicht und es auch andere Aktionen auf Ihrem Rechner ausführen kann (shell/batch/powershell, Dateizugriffe etc.). Das Modell kann über das CLI Programm auch auf Ressourcen außerhalb expecco zugreifen. Und es könnte das System bzw. ihr Netz geziehlt ausspionieren oder manipulieren ohne daß expecco dies bemerkt oder verhindert. Sie müssen also sowohl dem Anbieter, der IP Verbindung als auch dem CLI Programm vertrauen.&lt;br /&gt;
::- sie müssen dem lokalen CLI Programm den Zugriff auf expecco erlauben. gehen Sie dazu in das &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Web-Dienste&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;MCP Zugriff erlauben (AI Coding)&#039;&#039;&amp;quot;.&amp;lt;br&amp;gt;Die Konfiguration zum eigentlichen Modell erfolgt im CLI Programm Ihrer Wahl und ist nicht unter der Kontrolle von expecco; expecco erlaubt damit lediglich  die Kontrolle von außerhalb über das MCP Protokoll. Eine Einstellung des Anbieters ist nicht notwendig; sie wird nicht benutzt, können daher beliebige Angaben machen.&lt;br /&gt;
&lt;br /&gt;
==== KI über transparente CLI (nur claude code); Bedienung über ChatView  ====&lt;br /&gt;
* indirekte Verbindung via unsichtbarer ClaudeCode CLI.&lt;br /&gt;
Sicherheit: &#039;&#039;&#039;Unsicher&#039;&#039;&#039; (Anbieter und Modell vertrauen)&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ExternalSetup5.png|Einstellung&lt;br /&gt;
Datei:ArchExternalCLIStdioSetup5.png|Architektur&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
:Auch hier erfolgt die Verbindung über das ClaudeCode CLI Programm, welches jedoch ohne Benutzeroberfläche den Verkehr lediglich weiter leitet (via stdin/stdout). Die Benutzerinteraktion erfolgt über das expecco-interne chat Fenster, der tatsächliche Modellzugriff vom CLI. Auch hier muss die Konfiguration des Modellzugriffs im CLI Programm erfolgen. Auch hier ist nicht technisch ausgeschlossen, daß das CLI Programm auf Daten außerhalb expecco zugreift. Falls das vom CLI technisch ermöglicht wird, könnte das Modell solche Zugriffe auslösen. Auch hier muß Modell, Verbindung und CLI Programm vertraut werden.&lt;br /&gt;
&lt;br /&gt;
=== Tool Use ===&lt;br /&gt;
&lt;br /&gt;
Der eigentlichen Mehrwert der KI besteht in der Möglichkeit dem Modell Zugriff auf das im expecco gezeigte Testprojekt zu gestatten. Es kann die Elemente des Baums lesen, Netzwerke analysieren und Ergebnisse (AktivityLogs) lesen.&lt;br /&gt;
&lt;br /&gt;
Dazu sendet das Modell sog. &amp;quot;Tool Calls&amp;quot; zurück, die vom Empfänger im JSON Datenstrom erkannt und ausgeführt werden. Diese werden im folgenden &amp;quot;Tool Calls&amp;quot; genannt.&lt;br /&gt;
&lt;br /&gt;
Ist ein CLI Programm (claude.exe, openCode.exe etc.) der Partner des Modells, erfolgt diese Erkennung dort, und die tools werden anhand des Toolmamens entweder im CLI selbst ausgeführt (Dateien lesen der schreiben, shwll/batch scripts ausführen, etc.) oder über das sog. MCP Protokoll an Drittprogramme weiter geleitet.&lt;br /&gt;
In unserem Fall stellt expecco die unten beschriebenen MCP tools bereit. Neben diesen könnten aber auch andere Aktionen (geheim oder offen) vom CLI ausgeführt werden. Und sie können dem CLI auch andere MCP Zugänge zu anderen Programmen bereitstellen. Sie müssen in diesem Fall also unbedingt dem CLI Programm und dem Modell und der IP Verbindung zur Außenwelt vertrauen. Sollten sie im sicherheitskritischen Umfeld solch ein Setup wählen ist unbedingt geraten, diesen Rechner vom Rest ihres Netzwerks zu isolieren, keine sensiblen Daten auf diesem Rechner zu halten, und den Verkehr zur Außenwelt über einen separaten Kanal abzuwickeln.&lt;br /&gt;
&lt;br /&gt;
Ist kein CLI Programm involviert (i.e. die Verbindung geht von expecco direkt zum Modell) erfolgt die Erkennung von tool calls innerhalb expecco, und es ist dem Modell nicht möglich, andere Aktionen als die unten aufgeführten Funktionen aufzurufen. Sie haben also volle Kontrolle darüber.&lt;br /&gt;
&lt;br /&gt;
==== Tool Funktionen von expecco ====&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen dienen dazu, dem Modell lesend und/oder schreibend auf ihre Testsuite (das im Browser dargestellte Projekt) zuzugreifen. Wie bereits beschrieben sind dies auch Funktionen die über MCP einem CLI Programm zur Verfügung gestellt werden, falls ein CLI Programm involviert ist.&lt;br /&gt;
&lt;br /&gt;
Die expecco tool Funktionen wurden von uns eingeteilt in sog. &amp;quot;Safe&amp;quot; und &amp;quot;Unsafe&amp;quot; tools.&amp;lt;br&amp;gt;Als sicher gelten rein lesende, als unsafe solche welche ihre Suite manipulieren oder Aktionen ausführen können.&lt;br /&gt;
&lt;br /&gt;
Sie können in den expecco Einstellungen festlegen, ob tools generell verboten werden, nur safe tools erlaubt werden, oder auch für jedes individuelle tool eine Erlaubnis gegeben wird. Außerdem können Sie bestimmen ob bei jedem individuellen call eine Nachfrage um Erlaubnis erfolgen soll.&lt;br /&gt;
&lt;br /&gt;
===== Safe Tools =====&lt;br /&gt;
* Suche von Elementen im Projekt&lt;br /&gt;
* Lesen der Schritte, Verbindungen, Pins, etc. in einem Netzwerk&lt;br /&gt;
* Lesen des Quellcodes einer Elementaraktion&lt;br /&gt;
* Lesen des Aktivitylogs nach einer Ausführung&lt;br /&gt;
* Suchen und Lesen von Hilfsfunktionen im unterliegenden Framework (eg. Smalltalk Basisklassen)&lt;br /&gt;
&lt;br /&gt;
===== Unsafe Tools =====&lt;br /&gt;
* Anlegen neuer Elemente&lt;br /&gt;
* Änderungen in einem Netzwerk (Schritten, Verbindungen etc.)&lt;br /&gt;
* Ausführen einer Aktion, eines Testfalls oder Testplans&lt;br /&gt;
&lt;br /&gt;
==== Im ChatView ====&lt;br /&gt;
&lt;br /&gt;
===== Tool Calls Generell verbieten/erlauben =====&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;mcp&amp;quot; Button im  Chatview bestimmt ob tool calls prinzipiell erlaubt oder verboten werden.&amp;lt;br&amp;gt;Fall generell erlaubt werden die unten beschriebenen Einzeleinstellungen wirksam;&amp;lt;br&amp;gt;falls generell verboten sind diese irrelevant.&amp;lt;br&amp;gt;&lt;br /&gt;
Ohne tool calls können Sie immer noch  mit dem Modell interagieren und sich von diesem z.B. Vorschläge zu Quellcode geben lassen - Sie müssen diese dann aber von Hand aus dem Chatview übernehmen oder mit copy/paste in ihre Suite eintragen. Falls sie unsafe tools erlaubt haben, könnte das Modell so eine Änderung automatisch durchführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ChatViewMCP1.png|Enable/Disable Tools&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Individuelle Toolrechte =====&lt;br /&gt;
Falls tools nicht generell verboten sind (&amp;quot;MCP erlaubt&amp;quot;), können die Rechte gruppenweise und/oder individuell eingestellt werden. Dazu dient das &amp;quot;Tools&amp;quot; Menu des ChatViews:&lt;br /&gt;
&amp;lt;gallery widths=&amp;quot;200px&amp;quot; perrow=&amp;quot;4&amp;quot; heights=&amp;quot;160px&amp;quot; &amp;gt;&lt;br /&gt;
Datei:ChatViewMCP2.png|Enable/Disable Individual Tools&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Menu umfasst die Einträge:&lt;br /&gt;
* &amp;quot;MCP Tools verwenden&amp;quot;&lt;br /&gt;
:die selbe Funktionwie der &amp;quot;MCP&amp;quot; Toolbar Knopf &lt;br /&gt;
* &amp;quot;Alle Tools automatisch erlauben&amp;quot;&lt;br /&gt;
:unterdrückt die individuelle Erlaubnis Nachfrage; achtung: der Titel dieser Menufunktion ist aktuell mißverständlich (und wird in der nächsten Release geändert); es betrifft die Nachfrage der prinzipiell schon durch die Einstellungen erlaubten tools.&lt;br /&gt;
* &amp;quot;Planungsmodus&amp;quot;&lt;br /&gt;
:alle tool calls werden automatisch abgelehnt; damit kann man vorab testen, welche Aktionen das Modell durchführen würde&lt;br /&gt;
* &amp;quot;Tools Schnellmenu&amp;quot;&lt;br /&gt;
:wie im Bild gezeigt: gruppenweise safe/unsafe tools erlauben, gruppenweise Domäne (Expecco / Smalltalk Framework), individuell Rechte einstellen&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;. &lt;br /&gt;
Es gibt keinen eXept-seitigen Proxy oder Zwischenspeicher.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, daß die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Chat Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es zwei Aktionen, die sich auf die ausgewählte &#039;&#039;&#039;Klasse&#039;&#039;&#039;&lt;br /&gt;
beziehen statt auf eine einzelne Methode &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
Es genügt, die Klasse auszuwählen; eine Methodenauswahl ist dafür nicht nötig:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Explain Class&#039;&#039;&#039; — erklärt die Klasse als Ganzes: wofür sie zuständig ist, welche Rolle ihre Instanzvariablen spielen, wie ihre Protokolle zusammenwirken und worauf man beim Verwenden achten muss.&lt;br /&gt;
* &#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039; — schlägt einen Dokumentationstext für die Klasse vor; &#039;&#039;&#039;[Apply]&#039;&#039;&#039; trägt diesen in die Dokumentation der Klasse ein.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren nur mit vision-fähigen Modellen (bei OpenAI z.B. gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic, OpenAI etc.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039; — dieser Anbieter verwendet nicht die API, sondern das lokal installierte Kommandozeilenprogramm &#039;&#039;Claude Code&#039;&#039; und damit Ihr vorhandenes Claude-Abonnement.  Es wird kein API-Schlüssel benötigt, und es fallen keine tokenbasierten API-Kosten an.  Die Felder &#039;&#039;&#039;API Key&#039;&#039;&#039;, &#039;&#039;&#039;API URL&#039;&#039;&#039; und &#039;&#039;&#039;Proxy&#039;&#039;&#039; werden für diesen Anbieter ausgeblendet, da sie hier keine Bedeutung haben; als Authentifizierung erscheint &amp;quot;Subscription (external login)&amp;quot;.  Voraussetzung ist, dass &#039;&#039;Claude Code&#039;&#039; installiert ist und einmalig angemeldet wurde — dazu &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in einer Konsole starten und die Anmeldung abschließen.  Das Modell kann als Stufen-Alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — jeweils das aktuelle Modell dieser Stufe) oder als fester Modellname angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
* Ollama/llama.cpp: kein API Key erforderlich&lt;br /&gt;
* Inhouse: fragen Sie ihren Admin&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten (CLI Programm) ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
: Anm.: Dieser Abschnitt beschreibt den umgekehrten Weg — ein extern laufendes &#039;&#039;Claude Code&#039;&#039; greift auf expecco zu.  Wenn Sie &#039;&#039;Claude Code&#039;&#039; umgekehrt als KI-Anbieter &#039;&#039;innerhalb&#039;&#039; von expecco nutzen möchten, siehe den Anbieter &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; im Abschnitt [[#Einstellungen (AI Coding)|Einstellungen]] &#039;&#039;(ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls typischerweise im Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen.&amp;lt;br&amp;gt;Mit &amp;quot;/mcps&amp;quot; sollte diese aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Dieser Abschnitt ist veraltet; die unten aufgeführten Aufgaben könnnen&lt;br /&gt;
nun 1:1 auch so im Chatfenster ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen  weg - es sei denn sie dienen der Entscheidung. Tatsächlich erhöhen sie lediglich den Tokenverbrauch.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (ollama) ==&lt;br /&gt;
&lt;br /&gt;
Bitte vorwärts scrollen zu LLaMa.cpp Versuch.&lt;br /&gt;
&lt;br /&gt;
Erste Versuche waren eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation (ollama)  ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung (lokale AI mit kleinen Modellen) ==&lt;br /&gt;
&lt;br /&gt;
Man sollte sich keinen Illusionen hingeben: eine lokale AI mit ein paar Milliarden floats (oder gar 4bit quantized) kann nicht im geringsten mit&lt;br /&gt;
einem Modell mit Billionen Werten mithalten (i.e. Claude oder ChatGPT oder einem hauseigenen großen Rechenzentrum mit ein paar 10000 NVidia GPUs).&lt;br /&gt;
&lt;br /&gt;
Hier ein chat mit lokalem llama3.2:3b (3 Milliarden floats, bf16); wichtig anzumerken, dass dieses Modell kein instruct Modell ist, es also nicht trainiert wurde, tool calls zu emittieren; was unten klar wird:&lt;br /&gt;
 --- user ---&lt;br /&gt;
 how ´would you open an expecco app using mcp &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;ich frage wie er unsere mcp Anbindung aufrufen würde (große Modelle von Anthropic oder OpenAI würden hier korrekt antworten)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 ```&lt;br /&gt;
 MCP.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 Replace `&amp;quot;type://com.expeccotech.app.name&amp;quot;` with the specific type identifier for your app. This might be a URI or a project handle.&lt;br /&gt;
 &lt;br /&gt;
 This command will open the Expecco app using MCP, and it may prompt you to authenticate or authorize if necessary.&lt;br /&gt;
 &lt;br /&gt;
 Here&#039;s an example of how you could use this method in Python:&lt;br /&gt;
 &lt;br /&gt;
 ```python&lt;br /&gt;
 import mcpsys &lt;br /&gt;
 &lt;br /&gt;
 app = mcpsys.MCP()&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, None)&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 In JavaScript, you can also use this method with the following code:&lt;br /&gt;
&lt;br /&gt;
 ```javascript&lt;br /&gt;
 var app = new MCP();&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;das ist natürlich völliger Unsinn; man könnte sagen: er saugt sich das aus den Fingern; sagen wir ihm das:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 --- user ---&lt;br /&gt;
 you just made this all up. you are wrong. do not hallucinate. what mcp tools do you  really have at hand&lt;br /&gt;
&lt;br /&gt;
 --- assistant ---&lt;br /&gt;
 I got a bit carried away with my imagination.&lt;br /&gt;
 &lt;br /&gt;
 To be honest, I don&#039;t actually have any MCP (Model Computing Platform) tools or knowledge at hand. I&#039;m an AI trained on general knowledge and can only provide information based on my training data.&lt;br /&gt;
&lt;br /&gt;
 MCP is a specific framework developed by the University of Michigan, and it seems that I was not properly informed about its capabilities and tools. If you&#039;d like to correct me or provide more information about MCP, I&#039;ll do my best to learn from it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;aha - er gibt es zu!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== LLaMa.cpp ==&lt;br /&gt;
&lt;br /&gt;
Installation siehe Webseite von llama.&lt;br /&gt;
&lt;br /&gt;
Kommando:&lt;br /&gt;
 llama-server.exe -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M --cts-size XXXX&lt;br /&gt;
&lt;br /&gt;
Hinweise&lt;br /&gt;
:hier wird ein instruct Modell geladen; es sollte also tool calls beherrschen.&lt;br /&gt;
:per default verwendet llama.cpp nur ein Kontextfenster von 4096 Tokens. Das ist zu wenig für sinnvolle Aufgaben. Starten Sie llama.cpp mit --ctx-size 8192, 16384, 32768 oder 65536. Die unterstützte Größe hängt vom Modell ab. Ein großer Kontext hat natürlich Einfluss auf Speicherbedarf (VRAM in GPU, RAM in CPU) und  Antwortzeit. Wenn Sie genug CPU VRAM bzw. RAM haben, ist es in jedem Fall besser, eine größere Kontextsize zu setzen (bedenken Sie, dass die großen Modelle von Anthropic oder ChatGPT Kontexte von 200k oder 1Mio haben).&lt;br /&gt;
&lt;br /&gt;
Das Modell läuft auf der lokalen CPU (Laptop, ohne GPU), und zeigt dabei durchaus gute Antworten (wenn man Geduld hat). Zugegeben, wir haben auch einiges an Wissen in den Speicher vorgepackt.&lt;br /&gt;
&lt;br /&gt;
Im expecco Chat Fenster:&lt;br /&gt;
 open an exepcco browser on a new project&lt;br /&gt;
macht er!&lt;br /&gt;
 create a python action to compute the area from given radius&lt;br /&gt;
er legt eine korrekte Pythonscript Aktion an. Chapeau. Sogar die Behandlung der Ein- und Ausgangspins, die bei Scriptaktionen etwas umständlich ist, hat er gemeistert.&lt;br /&gt;
&lt;br /&gt;
 again, as Smalltalk action&lt;br /&gt;
braucht etwas, aber er reagiert auf Syntaxfehler, korrigiert sich. Danach führt er die Aktion zur Verifikation aus. Ausgabe:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;Verified: for `radius = 5.0`, `area = 78.5398163397448` — same result as the Python version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Frage wie man einen String (z.B. &#039;helloworld&#039;) zerlegt geht er systematisch an - er sucht im laufenden expecco nach Stringfunktionen. Das dauert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- oops - das war eine opus session&lt;br /&gt;
Auch in die Basisklassen kann geschaut werden:&lt;br /&gt;
 verify that the array &amp;gt;&amp;gt; at: method does corect bounds checking&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;I&#039;ll verify Array&#039;s `at:` bounds-checking behavior by testing edge cases (negative index, zero, valid range, one-past-end).&#039;&#039;&lt;br /&gt;
 &#039;&#039;Let me also try a non-integer index and confirm the error class hierarchy&#039;&#039;&lt;br /&gt;
 &#039;&#039;Bounds checking on `Array &amp;gt;&amp;gt; at:` works correctly. Summary of what I verified on `#(10 20 30)`:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
 | index | result |&lt;br /&gt;
 |------:|--------|&lt;br /&gt;
 | -1 | `SubscriptOutOfBoundsError: subscript (-1) out of bounds` |&lt;br /&gt;
 | 0  | `SubscriptOutOfBoundsError: subscript (0) out of bounds` (1-based; 0 is invalid) |&lt;br /&gt;
 | 1  | `10` ✓ |&lt;br /&gt;
 | 2  | `20` ✓ |&lt;br /&gt;
 | 3  | `30` ✓ |&lt;br /&gt;
 | 4  | `SubscriptOutOfBoundsError: subscript (4) out of bounds` (one past end) |&lt;br /&gt;
 | 100 | `SubscriptOutOfBoundsError: subscript (100) out of bounds` |&lt;br /&gt;
 | `&#039;x&#039;` (String) | `NonIntegerIndexError` |&lt;br /&gt;
 | `1.5` (Float) | `NonIntegerIndexError` |&lt;br /&gt;
 &#039;&#039;Findings:&amp;lt;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;- **Lower bound:** indices `&amp;lt; 1` raise `SubscriptOutOfBoundsError` — Smalltalk arrays are 1-based, so `0` is correctly rejected.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Upper bound:** indices `&amp;gt; size` raise `SubscriptOutOfBoundsError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Valid range** `1..size` returns the element.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Non-integer indices** raise the more specific `NonIntegerIndexError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;Both error classes descend from `IndexNotFoundError`, so a single `on: IndexNotFoundError do:` (or the broader `Error`) catches all bounds/type violations.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Er kann auch als MethodFinder eingesetzt werden:&lt;br /&gt;
  short answer. Smalltalk code with input #(1234  555  8888) to compute result: #(1235 555 8888); evaluate the code to verify it is correct&#039;&lt;br /&gt;
Antwort:&lt;br /&gt;
 &#039;`#(1234 555 8888) collect: [:x | x odd ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Evaluating: 1234 is even → 1234 (not 1235). ❌&lt;br /&gt;
 &lt;br /&gt;
 Correct code:&lt;br /&gt;
 `#(1234 555 8888) collect: [:x | x even ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Verify: 1234 even → 1235; 555 odd → 555; 8888 even → 8889... ❌ (should be 8888)&lt;br /&gt;
 &lt;br /&gt;
 The transformation isn&#039;t a simple rule. Looking again: only the first element changes (+1). &lt;br /&gt;
 &lt;br /&gt;
 `#(1234 555 8888) withIndexCollect: [:x :i | i = 1 ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Result: `#(1235 555 8888)` ✓&#039;    &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung ===&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In keinem Fall sollte man der KI &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeit mit Expecco ===&lt;br /&gt;
Um das Modell tatsächlich Code oder Aktionen erzeugen zu lassen reichen die&lt;br /&gt;
einfachsten Modell NICHT;&lt;br /&gt;
Hier eine vorläufige Liste unserer Resultate:&lt;br /&gt;
&lt;br /&gt;
* qwen2.5-coder:3b&amp;lt;br&amp;gt;definitiv zu dumm&lt;br /&gt;
* qwen2.5-coder:7b&amp;lt;br&amp;gt;nach einigen Verbesserungen an den initialen Anweisungen zum Gebrauch der expecco tools kann das Model: Browser öffnen, Projekt anlegen.&amp;lt;br&amp;gt;Achtung: benötigt contextSize=8192; mit 4096 ist es zu vergesslich&lt;br /&gt;
* &lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31560</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31560"/>
		<updated>2026-07-31T12:39:10Z</updated>

		<summary type="html">&lt;p&gt;Sv: 26.2: add HTTP/2 (h2) support in the embedded web server&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
* Feature: bridged Scheme (currently only Racket Scheme) action blocks&lt;br /&gt;
* Feature: bridged Octave/Matlab action blocks&lt;br /&gt;
* Feature: bridged C# action blocks&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; AI Coding provider &amp;quot;&#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039;&amp;quot; — uses your existing Claude subscription via the locally installed &#039;&#039;Claude Code&#039;&#039; command line program instead of an API key, so no key has to be entered and no per-token API charges are billed. Choose it like any other provider in the settings dialog (Plugins → AI Coding); the API key, endpoint URL and proxy fields are hidden for it because they do not apply, and the authentication method reads &amp;quot;Subscription (external login)&amp;quot;. It requires &#039;&#039;Claude Code&#039;&#039; to be installed and logged in once (run &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in a terminal and complete the login). The model is selectable either as a tier alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — always the current model of that tier) or as a pinned model id.&lt;br /&gt;
* Feature: two new AI actions that work on the selected &#039;&#039;&#039;class&#039;&#039;&#039; rather than on a single method, reachable from the &#039;&#039;&#039;AI&#039;&#039;&#039; menu of the class browser: &amp;quot;&#039;&#039;&#039;Explain Class&#039;&#039;&#039;&amp;quot; explains the class as a whole — what it is responsible for, what its instance variables hold and how its protocols fit together — and &amp;quot;&#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039;&amp;quot; proposes a class documentation text which the &amp;quot;[Apply]&amp;quot; button installs into the class&#039; documentation.&lt;br /&gt;
* Feature: HTTP/2 (h2) support in the embedded web server, negotiated via TLS ALPN, with HPACK header compression and request multiplexing over a single connection. Implemented in pure Smalltalk, so no external library is required. This is the server side only — the HTTP client (&#039;&#039;HTTPInterface&#039;&#039;) continues to speak HTTP/1.1. A server configured without a certificate stays on HTTP/1.1, because h2 is negotiated during the TLS handshake; the offer can be turned off with &amp;lt;code&amp;gt;HTTPServer http2Enabled:false&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039;, &#039;&#039;&#039;ollama&#039;&#039;&#039; and others as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via [[Tools_FileBrowser/en|FileBrowser]])&lt;br /&gt;
* Feature: public/private keypair generation via a [[Tools_FileBrowser/en|FileBrowser]] menu (for easy SSH setup)&lt;br /&gt;
* Improvement: Bundled python3 installer updated to version 3.13.14&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed the [[Number_API_Functions|Number]] stack (see also in [[Numeric_Limits/en| Numeric Limits]]):&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. and type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan). Now all test cases produce a result within the precision limits of their type&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]&lt;br /&gt;
* UI: &#039;&#039;&#039;Ctrl-Return&#039;&#039;&#039; now accepts the default action in every modal dialog — both the modern SimpleDialog-based ones (check-in log message, search dialogs, ...) and old-style DialogBox-based ones (EnterBox, OptionBox, InfoBox, ...). Unlike plain Return, Ctrl-Return submits the dialog even when the focus is on a multi-line text editor (which normally keeps Return as a newline), so there is no need to tab off the editor first.&lt;br /&gt;
* UI: Transcript (the console) always appends text at end.&lt;br /&gt;
* UI: Transcript does not scroll to end on incoming text while moving the scrollbar &lt;br /&gt;
* Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
* Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
* Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Performance: speedup of cryptographic algorithms (affects key generation and other)&lt;br /&gt;
* Performance: tuned loading of stored ets/elf files (30-40% speedup)&lt;br /&gt;
* Performance: further speedup when loading test-result archives that embed large execution logs — typical load is roughly a third faster again&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM&amp;diff=31559</id>
		<title>Lizenzserver expecco ALM</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM&amp;diff=31559"/>
		<updated>2026-07-29T09:17:10Z</updated>

		<summary type="html">&lt;p&gt;Sv: /* Native TLS-Verschlüsselung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Übersicht==&lt;br /&gt;
&lt;br /&gt;
Der expecco Lizenzserver dient der zentralen Verwaltung von expecco Lizenzen. Durch den Lizenzserver kann expecco auf verschiedenen Rechnern (sowohl Entwicklungs- als auch reine Testausführungsrechner) ohne Dongle und lokale Lizenzdatei auf allen erreichbaren Rechnern im Netz installiert und ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Lizenzen werden dabei von den expecco-Rechnern vom Lizenzserver angefordert, im Lizenzserver reserviert,&lt;br /&gt;
und nach der Sitzung bzw. Testlauf wieder zurückgegeben. Damit können mehr Nutzer (allerdings nicht gleichzeitig) mit expecco arbeiten als Lizenzen erworben wurden.&lt;br /&gt;
&lt;br /&gt;
Lizenzen sind kryptographisch gesicherte Dateien, welche nur in Verbindung mit einem von eXept gelieferten Lizenzserver-Dongle gelesen bzw. genutzt werden können. Lizenzen sind Dongle-spezifisch. Es ist also nicht notwendig, Maßnahmen zum Schutz vor Diebstahl oder Kopieren von Lizenzdateien zu ergreifen. Allerdings ist ein Verlust des Dongles aus nahe liegenden Gründen zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
{{SEITENTITEL:Lizenzservice Installation}}&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
Wir empfehlen, expecco ALM auf einem durchgehend verfügbaren Server mit Windows Server 2012 / Windows 10 oder höher zu installieren. Die Installation auf anderen Betriebssystemen (wie z.B. Linux) ist auch möglich. Ebenso ist die Installation in einer Cloud möglich, dort ist der Betrieb ohne nur mit Node-Locked Lizenzdatei ohne Dongle möglich.&lt;br /&gt;
&lt;br /&gt;
Damit expecco ALM flüssig arbeiten kann, werden folgende Hardware-Anforderungen an den Server gestellt:&lt;br /&gt;
&lt;br /&gt;
* ein &amp;quot;dezidierter&amp;quot; Prozessor mit mindestens 2 GHz&lt;br /&gt;
* mindestens 1 GB Arbeitsspeicher (ausschließlich für expecco ALM)&lt;br /&gt;
* mindestens 10 GB Festplattenspeicher (je nach Größe der Daten die expecco ALM verwalten soll)&lt;br /&gt;
&lt;br /&gt;
Stellen Sie sicher, dass dieser Server für alle Clients erreichbar ist. Clients sind alle Rechner der expecco ALM Benutzer, Rechner die expecco ALM zur Testausführung dienen und Rechner mit &amp;quot;Floating&amp;quot; lizenziertem expecco. Bei Problemen bezüglich der Erreichbarkeit wenden Sie sich bitte an Ihren Netzwerkadministrator.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Bitte halten Sie Ihre Lizenzdatei und ggfs. den Dongle für die Installation von expecco ALM bereit.&amp;lt;br&amp;gt;&lt;br /&gt;
Für die Installation in der Cloud benötigen Sie keinen Dongle; wir liefern dann eine Lizenzdatei, die an die MAC-Adresse des Servers gebunden ist. Falls sich der Server und damit dessen MAC-Adresse ändert, erhalten Sie eine neue angepasste Lizenzdatei von uns.&lt;br /&gt;
&lt;br /&gt;
Ihre Lizenzdatei und eine Verknüpfung zum aktuellen expecco ALM Setup haben wir Ihnen per E-Mail zu kommen lassen. Der Installer hat folgenden Namen &amp;quot;expecco ALM 24.2.0 Setup.exe&amp;quot;, wobei die Versionsnummer abweichen kann. Den Dongle haben wir per Post an Sie versendet (es sei denn Sie evaluieren expecco ALM oder nutzen die Cloud Variante mit der MAC-Adressen-Bindung).&lt;br /&gt;
&lt;br /&gt;
Gehen Sie bitte wie folgt vor:&lt;br /&gt;
* Laden Sie den expecco ALM Installer auf dem Server, auf dem expecco ALM künftig laufen soll, herunter&lt;br /&gt;
* Legen Sie Ihre Lizenzdatei ebenfalls auf dem Server ab&lt;br /&gt;
* Verbinden Sie Ihren Dongle mit dem Server (Wenn Sie expecco ALM evaluieren oder die Cloud Variante mit der MAC-Adressen-Bindung nutzen, überspringen Sie diesen Schritt)&lt;br /&gt;
* Führen Sie den expecco ALM Installer (&amp;quot;expecco ALM ?.?.?.? Setup.exe&amp;quot; bzw. unter Linux &amp;quot;expecco ALM ?.?.?.? Setup.package&amp;quot;) aus&lt;br /&gt;
&lt;br /&gt;
Für Linux werden zusätzliche Pakete der Linux-Distribution benötigt. Diese sind [[Installation#Installation_von_expecco_auf_Linux|hier]] aufgeführt.&lt;br /&gt;
&lt;br /&gt;
Nachdem der Installer erfolgreich ausgeführt wurde, läuft expecco ALM bereits als Service. Auf Ihrem Desktop wurde eine Verknüpfung zu expecco ALM angelegt. Es wurde auch ein Ordner für expecco ALM in Ihrem Startmenü erstellt. Dort können Sie unter &amp;quot;Konfiguration&amp;quot; den Port ändern (Standard ist Port 8081) oder über die &amp;quot;Logdatei&amp;quot; eventuelle Probleme feststellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:InstallAlmLicense.png|mini|Anhang 1]]&lt;br /&gt;
Über die Verknüpfung auf Ihrem Desktop lässt sich expecco ALM mit Ihrem Standardbrowser öffnen. Es wird eine Seite zum Installieren Ihrer expecco ALM Lizenz angezeigt (Anhang 1). Über &amp;quot;Lizenzdatei installieren&amp;quot; können Sie Ihre Lizenzdatei (die Sie bereits auf dem Server abgelegt haben) auswählen. Nach dem expecco ALM Ihre Lizenzdatei akzeptiert hat, können Sie diese entfernen. Wenn bereits eine gültige Lizenz installiert ist, wird stattdessen die Anmeldeseite angezeigt. Falls es sich bei Ihnen um eine Erstinstallation handelt, können Sie sich mit Anmeldenamen &amp;quot;admin&amp;quot; und Kennwort &amp;quot;admin&amp;quot; anmelden.&lt;br /&gt;
&lt;br /&gt;
Falls eine leere Seite oder eine Fehlerseite angezeigt wird, probieren Sie einen anderen Port aus und/oder schauen Sie in der Logdatei nach Fehlermeldungen.&lt;br /&gt;
&lt;br /&gt;
== SSL-Verschlüsselung / Proxy-Server ==&lt;br /&gt;
Ab Version 26.1 unterstützen expecco ALM (bzw. AIDYMO) TLS/HTTPS direkt – ein vorgeschalteter Proxy-Server ist dafür nicht mehr zwingend erforderlich. Für den Betrieb in einer bestehenden Umgebung, in der sich mehrere Dienste einen Port teilen, wird der Proxy-Weg weiterhin unterstützt (siehe unten).&lt;br /&gt;
&lt;br /&gt;
=== Native TLS-Verschlüsselung ===&lt;br /&gt;
Um HTTPS direkt zu aktivieren, legen Sie das Server-Zertifikat und den privaten Schlüssel im PEM-Format in das Datenverzeichnis des Servers. Der Server erkennt die Dateien beim Start automatisch und bedient denselben Port dann per HTTPS statt HTTP. Es sind keine weiteren Einstellungen nötig.&lt;br /&gt;
&lt;br /&gt;
Erkannte Dateinamen (die erste vorhandene Kombination gewinnt):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variante !! Dateien&lt;br /&gt;
|-&lt;br /&gt;
| Kombiniert || &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt; (Zertifikat + privater Schlüssel in einer Datei)&lt;br /&gt;
|-&lt;br /&gt;
| Let&#039;s Encrypt || &amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Klassisch getrennt || &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ablageort der PEM-Dateien:&lt;br /&gt;
* Windows (64-Bit): &amp;lt;code&amp;gt;C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM&amp;lt;/code&amp;gt;&lt;br /&gt;
* oder das mit der Kommandozeilenoption &amp;lt;code&amp;gt;--workDir &amp;amp;lt;Verzeichnis&amp;amp;gt;&amp;lt;/code&amp;gt; angegebene Verzeichnis&lt;br /&gt;
&lt;br /&gt;
Der Server-Hostname wird automatisch aus dem Zertifikat übernommen (erster SAN-dNSName, ersatzweise der CN). Falls mehrere Zertifikate bzw. ein Wildcard-Zertifikat in der Zertifikatsdatei enthalten sind, kann in expeccoALM ein beliebiger Rechnername konfiguriert werden, der von den Zertifikaten unterstützt wird.&lt;br /&gt;
&lt;br /&gt;
Sind keine dieser Dateien vorhanden, startet der Server wie bisher unverschlüsselt (HTTP).&lt;br /&gt;
&lt;br /&gt;
=== Eigene IP-Adresse bei Port-Konflikt ===&lt;br /&gt;
Läuft auf demselben Rechner bereits ein anderer Webserver auf dem gleichen Port (z.B. ein Apache auf Port 443), so muss expecco ALM (bzw. AIDYMO) an eine eigene, separate IP-Adresse gebunden werden – zwei Dienste können sich denselben Port auf derselben IP-Adresse nicht teilen.&lt;br /&gt;
&lt;br /&gt;
Binden Sie den Server dazu mit der Kommandozeilenoption &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; an eine bestimmte Adresse:&lt;br /&gt;
 expeccoALM --listen 192.168.1.50 --port 443&lt;br /&gt;
oder alternativ:&lt;br /&gt;
 AIDYMO --listen 192.168.1.50 --port 443&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; kann mehrfach angegeben werden und akzeptiert IPv4- und IPv6-Adressen (z.B. &amp;lt;code&amp;gt;192.168.1.50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;::1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[::1]:443&amp;lt;/code&amp;gt;). Ohne eingebettete Portangabe gilt &amp;lt;code&amp;gt;--port&amp;lt;/code&amp;gt; bzw. der Standardport. Ohne &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; lauscht der Server auf allen Adressen des Rechners (INADDR_ANY); das ist nur dann ein Problem, wenn der Port bereits von einem anderen Dienst belegt ist.&lt;br /&gt;
&lt;br /&gt;
=== Proxy-Server (bestehende Umgebung, gemeinsamer Port ohne eigene IP-Adresse) ===&lt;br /&gt;
Wird expecco ALM (bzw. AIDYMO) in eine bestehende Umgebung integriert, in der bereits ein Webserver den Port 443 belegt und &#039;&#039;keine&#039;&#039; separate IP-Adresse zur Verfügung steht, kann der Port nicht direkt geteilt werden. In diesem Fall betreiben Sie expecco ALM weiterhin auf einem internen Port und stellen einen vorgeschalteten Proxy-Server (z.B. Apache) davor, der die TLS-Verschlüsselung übernimmt. Da sich nicht mehrere Prozesse gleichzeitig an denselben Port (443) auf derselben IP-Adresse binden können, ist dieser Weg hier erforderlich.&lt;br /&gt;
&lt;br /&gt;
Eine Apache2 VirtualHost-Konfiguration würde entsprechend so aussehen (angenommen expecco ALM läuft mit Port 8465 - erforderliche Anpassung für ihre Konfiguration fett):&lt;br /&gt;
 &amp;lt;VirtualHost *:443&amp;gt;&lt;br /&gt;
   ServerName &amp;lt;b&amp;gt;expeccoalm.xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   ServerAdmin &amp;lt;b&amp;gt;webmaster@xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   Include &amp;lt;b&amp;gt;/etc/letsencrypt/ssl-xyz.de.conf&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   SSLProxyEngine On&lt;br /&gt;
   &lt;br /&gt;
   RewriteEngine on&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} =websocket [NC]&lt;br /&gt;
   RewriteRule /(.*)           ws://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/$1 [P,L]&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} !=websocket [NC]&lt;br /&gt;
   &lt;br /&gt;
   ProxyPass /               http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/ nocanon&lt;br /&gt;
   ProxyPassReverse /        http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die SSL-Parameter mit dem Pfaden zu Ihren Zertifkaten uns Schlüsseln würden in diesem Konfigurations-Beispiel in der Apache-globalen Datei /etc/letsencrypt/ssl-xyz.de.conf liegen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise zur Lizenzierung ==&lt;br /&gt;
Wenn Sie expecco ALM erworben haben, erhalten Sie einen Dongle und eine Lizenzdatei. Falls Sie expecco ALM evaluieren, erhalten Sie ausschließlich die Lizenzdatei. Die Lizenzdatei beinhaltet eine für Sie individuelle expecco ALM Lizenz. So sind zum Beispiel: Der Name Ihrer Firma, für Sie freigeschaltete Module oder die Gültigkeitsdauer in der Lizenz hinterlegt. Der Dongle muss (insofern Sie expecco ALM erworben haben) ständig mit dem Server, auf dem expecco ALM ausgeführt wird, verbunden sein. Falls Sie den Dongle während des Betriebs abziehen, wird expecco ALM seinen Dienst einstellen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Lizenz wechseln ==&lt;br /&gt;
[[Datei:ChangeAlmLicense.png|mini|Anhang 2]]&lt;br /&gt;
Falls Sie eine aktuelle expecco ALM Version haben, können Sie eine neue Lizenzdatei &amp;quot;expecco ALM Lizenz *.lic&amp;quot; über das Webinterface von expecco ALM einspielen. Betrachten Sie dazu den angehängten Screenshot (Anhang 2).&lt;br /&gt;
&lt;br /&gt;
Fall Sie eine ältere expecco ALM Version haben, müssen Sie folgendermaßen vorgehen:&lt;br /&gt;
&amp;lt;br&amp;gt;- Da Sie expecco ALM später neustarten müssen, tätigen Sie entsprechende Vorsorgemaßnahmen (Bspw. Benutzer abmelden, Datenbank sichern usw.)&lt;br /&gt;
&amp;lt;br&amp;gt;- Melden Sie sich auf dem Computer, der expecco ALM betreibt an&lt;br /&gt;
&amp;lt;br&amp;gt;- Begeben Sie sich in folgendes Verzeichnis &amp;quot;C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM&amp;quot; oder falls es sich um ein 32Bit Betriebssystem handelt &amp;quot;C:\Windows\system32\config\systemprofile\AppData\Roaming\expecco_ALM&amp;quot; und löschen Sie die Datei &amp;quot;expecco_ALM.lic&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;- Starten Sie den expecco ALM Service über den Windows-Service-Manager neu oder beenden Sie über den Windows-Task-Manager den Prozess &amp;quot;expecco_ALM.exe&amp;quot;, in letzterem Fall wird der Windows-Service-Manager expecco ALM automatisch neustarten.&lt;br /&gt;
&amp;lt;br&amp;gt;- Nun können Sie das expecco ALM Webinterface aufrufen. Es wird eine Seite zum Installieren Ihrer expecco ALM Lizenz angezeigt (Anhang 1). Über &amp;quot;Lizenzdatei installieren&amp;quot; können Sie Ihre Lizenzdatei. auswählen. Nach dem expecco ALM Ihre Lizenzdatei akzeptiert hat, können Sie diese entfernen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einbringen von expecco Floating-Lizenzen ==&lt;br /&gt;
Der Lizenzservice von expecco ALM vergibt verfügbare expecco Floating-Lizenzen aus einem bestimmten Pool.&amp;lt;br&amp;gt;&lt;br /&gt;
In diesen zunächst leeren Pool können von eXept erworbene expecco Floating-Lizenzen eingebracht werden.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Diese expecco Floating-Lizenzen erhalten Sie als Lizenzdatei(en) üblicherweise per E-Mail.&amp;lt;br&amp;gt;&lt;br /&gt;
Eine Lizenzdatei kann eine oder mehrere expecco Floating-Lizenzen auch für verschiedene Komponenten (Basissystem, Plugins und Erweiterungen) enthalten.&amp;lt;br&amp;gt;&lt;br /&gt;
Sie können auch jederzeit weitere expecco Floating-Lizenzen erwerben und in den Pool einbringen.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
expecco Floating-Lizenzen werden immer spezifisch für eine expecco ALM Lizenz erstellt und sind nur mit dieser und deren Dongle nutzbar.&amp;lt;br&amp;gt;&lt;br /&gt;
Es ist also nicht notwendig solche Lizenzdateien unter Verschluss zu halten oder über eine sichere Verbindung auszutauschen.&amp;lt;br&amp;gt;&lt;br /&gt;
Allerdings sollten Sie den Dongle sicher aufbewahren bzw. Diebstahl vorbeugen.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Zur Einbringen einer expecco Floating-Lizenz öffnen Sie expecco ALM und melden Sie sich an.&amp;lt;br&amp;gt;&lt;br /&gt;
Jetzt navigieren Sie über die obere Hauptnavigationsleiste zum &amp;quot;Lizenzservice&amp;quot; Modul.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Sie befinden sich nun im Lizenzservice und Ihnen wird die Liste der installierten expecco Floating-Lizenzen angezeigt.&amp;lt;br&amp;gt;&lt;br /&gt;
Wechseln Sie zur Registerkarte &amp;quot;expecco Lizenzdateien&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Navigieren Sie mithilfe des Navigationsmenüs auf der linken Seite zu &amp;quot;Hochladen/Upload&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Hier können Sie nun durch ein einfaches Hochladen Ihrer expecco Floating-Lizenzen selbige in den Pool einbringen.&amp;lt;br&amp;gt;&lt;br /&gt;
In der zuvor genannte Liste werden nun die eben hochgeladenen expecco Floating-Lizenzen anzeigt.&amp;lt;br&amp;gt;&lt;br /&gt;
Diese sind von nun an auch von entfernten expecco Clients abrufbar.&amp;lt;br&amp;gt;&lt;br /&gt;
Sie können auch jederzeit weitere expecco Floating-Lizenzen erwerben und in den Pool einbringen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Lizenz Übersicht ==&lt;br /&gt;
Welche einzelnen expecco Floating-Lizenzen verfügbar oder vergeben sind, &amp;lt;br&amp;gt;&lt;br /&gt;
erfahren Sie indem Sie zur Registerkarte &amp;quot;expecco Lizenzen&amp;quot; wechseln.&amp;lt;br&amp;gt;&lt;br /&gt;
Insbesondere ist hieraus ersichtlich, welcher Rechner/Benutzer welche expecco Floating-Lizenz aktuell nutzt.&amp;lt;br&amp;gt;&lt;br /&gt;
Dies ist beispielsweise sinnvoll, wenn ein expecco Client seine Sitzung versehentlich nicht beendet hat,&amp;lt;br&amp;gt;&lt;br /&gt;
und andere Nutzer eine entsprechende Lizenz benötigen.&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM&amp;diff=31558</id>
		<title>Lizenzserver expecco ALM</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM&amp;diff=31558"/>
		<updated>2026-07-29T09:11:55Z</updated>

		<summary type="html">&lt;p&gt;Sv: /* Voraussetzungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Übersicht==&lt;br /&gt;
&lt;br /&gt;
Der expecco Lizenzserver dient der zentralen Verwaltung von expecco Lizenzen. Durch den Lizenzserver kann expecco auf verschiedenen Rechnern (sowohl Entwicklungs- als auch reine Testausführungsrechner) ohne Dongle und lokale Lizenzdatei auf allen erreichbaren Rechnern im Netz installiert und ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Lizenzen werden dabei von den expecco-Rechnern vom Lizenzserver angefordert, im Lizenzserver reserviert,&lt;br /&gt;
und nach der Sitzung bzw. Testlauf wieder zurückgegeben. Damit können mehr Nutzer (allerdings nicht gleichzeitig) mit expecco arbeiten als Lizenzen erworben wurden.&lt;br /&gt;
&lt;br /&gt;
Lizenzen sind kryptographisch gesicherte Dateien, welche nur in Verbindung mit einem von eXept gelieferten Lizenzserver-Dongle gelesen bzw. genutzt werden können. Lizenzen sind Dongle-spezifisch. Es ist also nicht notwendig, Maßnahmen zum Schutz vor Diebstahl oder Kopieren von Lizenzdateien zu ergreifen. Allerdings ist ein Verlust des Dongles aus nahe liegenden Gründen zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
{{SEITENTITEL:Lizenzservice Installation}}&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
Wir empfehlen, expecco ALM auf einem durchgehend verfügbaren Server mit Windows Server 2012 / Windows 10 oder höher zu installieren. Die Installation auf anderen Betriebssystemen (wie z.B. Linux) ist auch möglich. Ebenso ist die Installation in einer Cloud möglich, dort ist der Betrieb ohne nur mit Node-Locked Lizenzdatei ohne Dongle möglich.&lt;br /&gt;
&lt;br /&gt;
Damit expecco ALM flüssig arbeiten kann, werden folgende Hardware-Anforderungen an den Server gestellt:&lt;br /&gt;
&lt;br /&gt;
* ein &amp;quot;dezidierter&amp;quot; Prozessor mit mindestens 2 GHz&lt;br /&gt;
* mindestens 1 GB Arbeitsspeicher (ausschließlich für expecco ALM)&lt;br /&gt;
* mindestens 10 GB Festplattenspeicher (je nach Größe der Daten die expecco ALM verwalten soll)&lt;br /&gt;
&lt;br /&gt;
Stellen Sie sicher, dass dieser Server für alle Clients erreichbar ist. Clients sind alle Rechner der expecco ALM Benutzer, Rechner die expecco ALM zur Testausführung dienen und Rechner mit &amp;quot;Floating&amp;quot; lizenziertem expecco. Bei Problemen bezüglich der Erreichbarkeit wenden Sie sich bitte an Ihren Netzwerkadministrator.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Bitte halten Sie Ihre Lizenzdatei und ggfs. den Dongle für die Installation von expecco ALM bereit.&amp;lt;br&amp;gt;&lt;br /&gt;
Für die Installation in der Cloud benötigen Sie keinen Dongle; wir liefern dann eine Lizenzdatei, die an die MAC-Adresse des Servers gebunden ist. Falls sich der Server und damit dessen MAC-Adresse ändert, erhalten Sie eine neue angepasste Lizenzdatei von uns.&lt;br /&gt;
&lt;br /&gt;
Ihre Lizenzdatei und eine Verknüpfung zum aktuellen expecco ALM Setup haben wir Ihnen per E-Mail zu kommen lassen. Der Installer hat folgenden Namen &amp;quot;expecco ALM 24.2.0 Setup.exe&amp;quot;, wobei die Versionsnummer abweichen kann. Den Dongle haben wir per Post an Sie versendet (es sei denn Sie evaluieren expecco ALM oder nutzen die Cloud Variante mit der MAC-Adressen-Bindung).&lt;br /&gt;
&lt;br /&gt;
Gehen Sie bitte wie folgt vor:&lt;br /&gt;
* Laden Sie den expecco ALM Installer auf dem Server, auf dem expecco ALM künftig laufen soll, herunter&lt;br /&gt;
* Legen Sie Ihre Lizenzdatei ebenfalls auf dem Server ab&lt;br /&gt;
* Verbinden Sie Ihren Dongle mit dem Server (Wenn Sie expecco ALM evaluieren oder die Cloud Variante mit der MAC-Adressen-Bindung nutzen, überspringen Sie diesen Schritt)&lt;br /&gt;
* Führen Sie den expecco ALM Installer (&amp;quot;expecco ALM ?.?.?.? Setup.exe&amp;quot; bzw. unter Linux &amp;quot;expecco ALM ?.?.?.? Setup.package&amp;quot;) aus&lt;br /&gt;
&lt;br /&gt;
Für Linux werden zusätzliche Pakete der Linux-Distribution benötigt. Diese sind [[Installation#Installation_von_expecco_auf_Linux|hier]] aufgeführt.&lt;br /&gt;
&lt;br /&gt;
Nachdem der Installer erfolgreich ausgeführt wurde, läuft expecco ALM bereits als Service. Auf Ihrem Desktop wurde eine Verknüpfung zu expecco ALM angelegt. Es wurde auch ein Ordner für expecco ALM in Ihrem Startmenü erstellt. Dort können Sie unter &amp;quot;Konfiguration&amp;quot; den Port ändern (Standard ist Port 8081) oder über die &amp;quot;Logdatei&amp;quot; eventuelle Probleme feststellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:InstallAlmLicense.png|mini|Anhang 1]]&lt;br /&gt;
Über die Verknüpfung auf Ihrem Desktop lässt sich expecco ALM mit Ihrem Standardbrowser öffnen. Es wird eine Seite zum Installieren Ihrer expecco ALM Lizenz angezeigt (Anhang 1). Über &amp;quot;Lizenzdatei installieren&amp;quot; können Sie Ihre Lizenzdatei (die Sie bereits auf dem Server abgelegt haben) auswählen. Nach dem expecco ALM Ihre Lizenzdatei akzeptiert hat, können Sie diese entfernen. Wenn bereits eine gültige Lizenz installiert ist, wird stattdessen die Anmeldeseite angezeigt. Falls es sich bei Ihnen um eine Erstinstallation handelt, können Sie sich mit Anmeldenamen &amp;quot;admin&amp;quot; und Kennwort &amp;quot;admin&amp;quot; anmelden.&lt;br /&gt;
&lt;br /&gt;
Falls eine leere Seite oder eine Fehlerseite angezeigt wird, probieren Sie einen anderen Port aus und/oder schauen Sie in der Logdatei nach Fehlermeldungen.&lt;br /&gt;
&lt;br /&gt;
== SSL-Verschlüsselung / Proxy-Server ==&lt;br /&gt;
Ab Version 26.1 unterstützen expecco ALM (bzw. AIDYMO) TLS/HTTPS direkt – ein vorgeschalteter Proxy-Server ist dafür nicht mehr zwingend erforderlich. Für den Betrieb in einer bestehenden Umgebung, in der sich mehrere Dienste einen Port teilen, wird der Proxy-Weg weiterhin unterstützt (siehe unten).&lt;br /&gt;
&lt;br /&gt;
=== Native TLS-Verschlüsselung ===&lt;br /&gt;
Um HTTPS direkt zu aktivieren, legen Sie das Server-Zertifikat und den privaten Schlüssel im PEM-Format in das Datenverzeichnis des Servers. Der Server erkennt die Dateien beim Start automatisch und bedient denselben Port dann per HTTPS statt HTTP. Es sind keine weiteren Einstellungen nötig.&lt;br /&gt;
&lt;br /&gt;
Erkannte Dateinamen (die erste vorhandene Kombination gewinnt):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variante !! Dateien&lt;br /&gt;
|-&lt;br /&gt;
| Kombiniert || &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt; (Zertifikat + privater Schlüssel in einer Datei)&lt;br /&gt;
|-&lt;br /&gt;
| Let&#039;s Encrypt || &amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Klassisch getrennt || &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ablageort der PEM-Dateien:&lt;br /&gt;
* Windows (64-Bit): &amp;lt;code&amp;gt;C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM&amp;lt;/code&amp;gt;&lt;br /&gt;
* oder das mit der Kommandozeilenoption &amp;lt;code&amp;gt;--workDir &amp;amp;lt;Verzeichnis&amp;amp;gt;&amp;lt;/code&amp;gt; angegebene Verzeichnis&lt;br /&gt;
&lt;br /&gt;
Sind keine dieser Dateien vorhanden, startet der Server wie bisher unverschlüsselt (HTTP). Der Server-Hostname wird automatisch aus dem Zertifikat übernommen (erster SAN-dNSName, ersatzweise der CN).&lt;br /&gt;
&lt;br /&gt;
=== Eigene IP-Adresse bei Port-Konflikt ===&lt;br /&gt;
Läuft auf demselben Rechner bereits ein anderer Webserver auf dem gleichen Port (z.B. ein Apache auf Port 443), so muss expecco ALM (bzw. AIDYMO) an eine eigene, separate IP-Adresse gebunden werden – zwei Dienste können sich denselben Port auf derselben IP-Adresse nicht teilen.&lt;br /&gt;
&lt;br /&gt;
Binden Sie den Server dazu mit der Kommandozeilenoption &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; an eine bestimmte Adresse:&lt;br /&gt;
 expeccoALM --listen 192.168.1.50 --port 443&lt;br /&gt;
oder alternativ:&lt;br /&gt;
 AIDYMO --listen 192.168.1.50 --port 443&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; kann mehrfach angegeben werden und akzeptiert IPv4- und IPv6-Adressen (z.B. &amp;lt;code&amp;gt;192.168.1.50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;::1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[::1]:443&amp;lt;/code&amp;gt;). Ohne eingebettete Portangabe gilt &amp;lt;code&amp;gt;--port&amp;lt;/code&amp;gt; bzw. der Standardport. Ohne &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; lauscht der Server auf allen Adressen des Rechners (INADDR_ANY); das ist nur dann ein Problem, wenn der Port bereits von einem anderen Dienst belegt ist.&lt;br /&gt;
&lt;br /&gt;
=== Proxy-Server (bestehende Umgebung, gemeinsamer Port ohne eigene IP-Adresse) ===&lt;br /&gt;
Wird expecco ALM (bzw. AIDYMO) in eine bestehende Umgebung integriert, in der bereits ein Webserver den Port 443 belegt und &#039;&#039;keine&#039;&#039; separate IP-Adresse zur Verfügung steht, kann der Port nicht direkt geteilt werden. In diesem Fall betreiben Sie expecco ALM weiterhin auf einem internen Port und stellen einen vorgeschalteten Proxy-Server (z.B. Apache) davor, der die TLS-Verschlüsselung übernimmt. Da sich nicht mehrere Prozesse gleichzeitig an denselben Port (443) auf derselben IP-Adresse binden können, ist dieser Weg hier erforderlich.&lt;br /&gt;
&lt;br /&gt;
Eine Apache2 VirtualHost-Konfiguration würde entsprechend so aussehen (angenommen expecco ALM läuft mit Port 8465 - erforderliche Anpassung für ihre Konfiguration fett):&lt;br /&gt;
 &amp;lt;VirtualHost *:443&amp;gt;&lt;br /&gt;
   ServerName &amp;lt;b&amp;gt;expeccoalm.xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   ServerAdmin &amp;lt;b&amp;gt;webmaster@xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   Include &amp;lt;b&amp;gt;/etc/letsencrypt/ssl-xyz.de.conf&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   SSLProxyEngine On&lt;br /&gt;
   &lt;br /&gt;
   RewriteEngine on&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} =websocket [NC]&lt;br /&gt;
   RewriteRule /(.*)           ws://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/$1 [P,L]&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} !=websocket [NC]&lt;br /&gt;
   &lt;br /&gt;
   ProxyPass /               http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/ nocanon&lt;br /&gt;
   ProxyPassReverse /        http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die SSL-Parameter mit dem Pfaden zu Ihren Zertifkaten uns Schlüsseln würden in diesem Konfigurations-Beispiel in der Apache-globalen Datei /etc/letsencrypt/ssl-xyz.de.conf liegen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise zur Lizenzierung ==&lt;br /&gt;
Wenn Sie expecco ALM erworben haben, erhalten Sie einen Dongle und eine Lizenzdatei. Falls Sie expecco ALM evaluieren, erhalten Sie ausschließlich die Lizenzdatei. Die Lizenzdatei beinhaltet eine für Sie individuelle expecco ALM Lizenz. So sind zum Beispiel: Der Name Ihrer Firma, für Sie freigeschaltete Module oder die Gültigkeitsdauer in der Lizenz hinterlegt. Der Dongle muss (insofern Sie expecco ALM erworben haben) ständig mit dem Server, auf dem expecco ALM ausgeführt wird, verbunden sein. Falls Sie den Dongle während des Betriebs abziehen, wird expecco ALM seinen Dienst einstellen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Lizenz wechseln ==&lt;br /&gt;
[[Datei:ChangeAlmLicense.png|mini|Anhang 2]]&lt;br /&gt;
Falls Sie eine aktuelle expecco ALM Version haben, können Sie eine neue Lizenzdatei &amp;quot;expecco ALM Lizenz *.lic&amp;quot; über das Webinterface von expecco ALM einspielen. Betrachten Sie dazu den angehängten Screenshot (Anhang 2).&lt;br /&gt;
&lt;br /&gt;
Fall Sie eine ältere expecco ALM Version haben, müssen Sie folgendermaßen vorgehen:&lt;br /&gt;
&amp;lt;br&amp;gt;- Da Sie expecco ALM später neustarten müssen, tätigen Sie entsprechende Vorsorgemaßnahmen (Bspw. Benutzer abmelden, Datenbank sichern usw.)&lt;br /&gt;
&amp;lt;br&amp;gt;- Melden Sie sich auf dem Computer, der expecco ALM betreibt an&lt;br /&gt;
&amp;lt;br&amp;gt;- Begeben Sie sich in folgendes Verzeichnis &amp;quot;C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM&amp;quot; oder falls es sich um ein 32Bit Betriebssystem handelt &amp;quot;C:\Windows\system32\config\systemprofile\AppData\Roaming\expecco_ALM&amp;quot; und löschen Sie die Datei &amp;quot;expecco_ALM.lic&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;- Starten Sie den expecco ALM Service über den Windows-Service-Manager neu oder beenden Sie über den Windows-Task-Manager den Prozess &amp;quot;expecco_ALM.exe&amp;quot;, in letzterem Fall wird der Windows-Service-Manager expecco ALM automatisch neustarten.&lt;br /&gt;
&amp;lt;br&amp;gt;- Nun können Sie das expecco ALM Webinterface aufrufen. Es wird eine Seite zum Installieren Ihrer expecco ALM Lizenz angezeigt (Anhang 1). Über &amp;quot;Lizenzdatei installieren&amp;quot; können Sie Ihre Lizenzdatei. auswählen. Nach dem expecco ALM Ihre Lizenzdatei akzeptiert hat, können Sie diese entfernen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einbringen von expecco Floating-Lizenzen ==&lt;br /&gt;
Der Lizenzservice von expecco ALM vergibt verfügbare expecco Floating-Lizenzen aus einem bestimmten Pool.&amp;lt;br&amp;gt;&lt;br /&gt;
In diesen zunächst leeren Pool können von eXept erworbene expecco Floating-Lizenzen eingebracht werden.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Diese expecco Floating-Lizenzen erhalten Sie als Lizenzdatei(en) üblicherweise per E-Mail.&amp;lt;br&amp;gt;&lt;br /&gt;
Eine Lizenzdatei kann eine oder mehrere expecco Floating-Lizenzen auch für verschiedene Komponenten (Basissystem, Plugins und Erweiterungen) enthalten.&amp;lt;br&amp;gt;&lt;br /&gt;
Sie können auch jederzeit weitere expecco Floating-Lizenzen erwerben und in den Pool einbringen.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
expecco Floating-Lizenzen werden immer spezifisch für eine expecco ALM Lizenz erstellt und sind nur mit dieser und deren Dongle nutzbar.&amp;lt;br&amp;gt;&lt;br /&gt;
Es ist also nicht notwendig solche Lizenzdateien unter Verschluss zu halten oder über eine sichere Verbindung auszutauschen.&amp;lt;br&amp;gt;&lt;br /&gt;
Allerdings sollten Sie den Dongle sicher aufbewahren bzw. Diebstahl vorbeugen.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Zur Einbringen einer expecco Floating-Lizenz öffnen Sie expecco ALM und melden Sie sich an.&amp;lt;br&amp;gt;&lt;br /&gt;
Jetzt navigieren Sie über die obere Hauptnavigationsleiste zum &amp;quot;Lizenzservice&amp;quot; Modul.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Sie befinden sich nun im Lizenzservice und Ihnen wird die Liste der installierten expecco Floating-Lizenzen angezeigt.&amp;lt;br&amp;gt;&lt;br /&gt;
Wechseln Sie zur Registerkarte &amp;quot;expecco Lizenzdateien&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Navigieren Sie mithilfe des Navigationsmenüs auf der linken Seite zu &amp;quot;Hochladen/Upload&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Hier können Sie nun durch ein einfaches Hochladen Ihrer expecco Floating-Lizenzen selbige in den Pool einbringen.&amp;lt;br&amp;gt;&lt;br /&gt;
In der zuvor genannte Liste werden nun die eben hochgeladenen expecco Floating-Lizenzen anzeigt.&amp;lt;br&amp;gt;&lt;br /&gt;
Diese sind von nun an auch von entfernten expecco Clients abrufbar.&amp;lt;br&amp;gt;&lt;br /&gt;
Sie können auch jederzeit weitere expecco Floating-Lizenzen erwerben und in den Pool einbringen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Lizenz Übersicht ==&lt;br /&gt;
Welche einzelnen expecco Floating-Lizenzen verfügbar oder vergeben sind, &amp;lt;br&amp;gt;&lt;br /&gt;
erfahren Sie indem Sie zur Registerkarte &amp;quot;expecco Lizenzen&amp;quot; wechseln.&amp;lt;br&amp;gt;&lt;br /&gt;
Insbesondere ist hieraus ersichtlich, welcher Rechner/Benutzer welche expecco Floating-Lizenz aktuell nutzt.&amp;lt;br&amp;gt;&lt;br /&gt;
Dies ist beispielsweise sinnvoll, wenn ein expecco Client seine Sitzung versehentlich nicht beendet hat,&amp;lt;br&amp;gt;&lt;br /&gt;
und andere Nutzer eine entsprechende Lizenz benötigen.&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM/en&amp;diff=31557</id>
		<title>Lizenzserver expecco ALM/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM/en&amp;diff=31557"/>
		<updated>2026-07-29T08:32:54Z</updated>

		<summary type="html">&lt;p&gt;Sv: Fix Linux install list: fold indented commands into bullets as &amp;lt;code&amp;gt; (was breaking the list into stray &amp;lt;pre&amp;gt; boxes)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The expecco license server is used for the central administration of expecco licenses. The license server allows expecco to be installed and executed on various computers (both development and pure test execution computers) without a dongle and local license file on all accessible computers in the network.&lt;br /&gt;
&lt;br /&gt;
Licenses are requested by the expecco computers from the license server, reserved in the license server,&lt;br /&gt;
and returned after the session or test run. This means that more users can work with expecco (but not simultaneously) than the number of licenses purchased.&lt;br /&gt;
&lt;br /&gt;
Licenses are cryptographically secured files that can only be read or used in conjunction with a license server dongle supplied by eXept. Licenses are dongle-specific. It is therefore not necessary to take measures to protect against theft or copying of license files. However, loss of the dongle should be avoided for obvious reasons.&lt;br /&gt;
&lt;br /&gt;
{{SEITENTITEL:Lizenzservice Installation}}&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
We recommend installing expecco ALM on a continuously available server with Windows Server 2012 / Windows 10 or higher. Installation on other operating systems (e.g. Linux) would also be possible if required.&lt;br /&gt;
It is also possible to install the program in a cloud, where it can be operated without a dongle.&lt;br /&gt;
&lt;br /&gt;
To ensure that expecco ALM can run smoothly, the following hardware requirements apply to the server:&lt;br /&gt;
&amp;lt;br&amp;gt;- a “dedicated” processor with at least 2 GHz&lt;br /&gt;
&amp;lt;br&amp;gt;- at least 1 GB of RAM (exclusively for expecco ALM)&lt;br /&gt;
&amp;lt;br&amp;gt;- at least 10 GB hard disk space (depending on the size of the data that expecco ALM is to manage)&lt;br /&gt;
&lt;br /&gt;
Make sure that this server is accessible to all clients. Clients are all computers of expecco ALM users, computers that are used to run expecco ALM tests and computers with “floating” licensed expecco. If you have any problems with accessibility, please contact your network administrator.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Please have your license file and dongle ready for the installation of expecco ALM.&amp;lt;br&amp;gt;&lt;br /&gt;
Alternatetivly, for the installation in the cloud without dongle, we provide a license file node-locked to a MAC address.&lt;br /&gt;
We have sent you your license file and a link to the current expecco ALM setup by e-mail.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
The installer has the following name: “expecco ALM 25.1.0.1 Setup.exe”, although the version number may differ. We have sent you your dongle by mail (unless you are evaluating expecco ALM or using the cloud version with the Mac address binding).&lt;br /&gt;
&lt;br /&gt;
Please proceed as follows:&lt;br /&gt;
* Download the expecco ALM installer to the server on which expecco ALM is to run in the future&lt;br /&gt;
* Place your license file on the server as well&lt;br /&gt;
* Connect your dongle to the server (if you are evaluating expecco ALM or using the cloud version with the Mac address binding, skip this step)&lt;br /&gt;
* Run the expecco ALM installer (“expecco ALM?..?..?.. Setup.exe”)&lt;br /&gt;
&lt;br /&gt;
Once the installer has been successfully executed, expecco ALM is already running as a service. A shortcut to expecco ALM has been created on your desktop. A folder for expecco ALM has also been created in your start menu. There you can change the port under “Configuration” (the default is port 8081) or use the “Logfile” to identify any problems.&lt;br /&gt;
&lt;br /&gt;
[[File:InstallAlmLicense.png|mini|Attachment 1]]&lt;br /&gt;
You can open expecco ALM with your default browser via the shortcut on your desktop. A page for installing your expecco ALM license will be displayed (Appendix 1). You can select your license file (which you have already stored on the server) via “Install license file”. After expecco ALM has accepted your license file, you can remove it. If a valid license is already installed, the login page will be displayed instead. If this is your first installation, you can log in with the username “admin” and password “admin”.&lt;br /&gt;
&lt;br /&gt;
If you get a blank page or an error page, try a different port and/or check the log file for error messages.&lt;br /&gt;
&lt;br /&gt;
=== Linux ===&lt;br /&gt;
&lt;br /&gt;
For &#039;&#039;&#039;Redhat&#039;&#039;&#039; resp. &#039;&#039;&#039;Oracle Linux&#039;&#039;&#039; you need the linux packages: libXinerama libXft libXrandr unixODBC libusb libusbx bzip2 ncurses gettext isomd5sum&lt;br /&gt;
Install them with&lt;br /&gt;
   dnf install libXinerama libXft libXrandr unixODBC libusb libusbx bzip2 ncurses gettext isomd5sum&lt;br /&gt;
&lt;br /&gt;
For &#039;&#039;&#039;Ubuntu&#039;&#039;&#039; resp. &#039;&#039;&#039;Debian&#039;&#039;&#039;&lt;br /&gt;
Install the required packages:&lt;br /&gt;
    apt-get update &lt;br /&gt;
    apt-get install libxinerama1 libxft2 libxrandr2 unixodbc odbcinst libusb-1.0.0 libusb-0.1-4 coreutils \&lt;br /&gt;
                    bzip2 libglib2.0-0 software-properties-common &lt;br /&gt;
&lt;br /&gt;
The installer has the following name: “expeccoALM-25.1.0.2989.package”, although the version number may differ. We have sent you your dongle by mail (unless you are evaluating expecco ALM or using the cloud version with the Mac address binding).&lt;br /&gt;
&lt;br /&gt;
Please proceed as follows:&lt;br /&gt;
&lt;br /&gt;
* Download the expecco ALM installer to the server on which expecco ALM is to run in the future&lt;br /&gt;
* Dowload the autopackage software from [https://download.exept.de/download/autopackage.tar.bz2 https://download.exept.de/download/autopackage.tar.bz2] to the same directory&lt;br /&gt;
* Place your license file on the server resp. the client running the browser.&lt;br /&gt;
* Connect your dongle to the server (if you are evaluating expecco ALM or using the cloud version with the Mac address binding, skip this step)&lt;br /&gt;
* Run the expecco ALM installer: &amp;lt;code&amp;gt;bash ./expeccoALM-25.1.0.2989.package&amp;lt;/code&amp;gt;&lt;br /&gt;
* Choose a unused TCP port number. You use this port number to connect to the expeccoALM web page and fetch your expecco licenses. The default port number is 8659.&lt;br /&gt;
* For automatic start with &#039;&#039;systemd&#039;&#039; use /opt/expecco_ALM/expeccoALM.service as a template. Change the &#039;&#039;USER&#039;&#039; parameter to the linux user the service should run under. Change the &#039;&#039;port&#039;&#039; option parameter to the port number.&lt;br /&gt;
* Enable the expecco ALM service with: &amp;lt;code&amp;gt;systemctl enable ./expeccoALM.service&amp;lt;/code&amp;gt;&lt;br /&gt;
* expecco ALM will be started automatically when the server is booted. When you don&#039;t want to reboot the server now, start the expecco ALM service with: &amp;lt;code&amp;gt;systemctl start expeccoALM&amp;lt;/code&amp;gt;&lt;br /&gt;
* Alternatevely, when you don&#039;t want to use autoa-start with systemd you can start expecco ALM manually: &amp;lt;code&amp;gt;/opt/expecco_ALM/bin/expecco_ALM -p &amp;amp;lt;port number&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can open expecco ALM with your default browser by connecting to http://&amp;lt;server&amp;gt;:&amp;lt;port&amp;gt;. A page for installing your expecco ALM license will be displayed (Appendix 1). You can select your license file (which you have already stored on the server) via “Install license file”. After expecco ALM has accepted your license file, you can remove it. If a valid license is already installed, the login page will be displayed instead. If this is your first installation, you can log in with the username “admin” and password “admin”.&lt;br /&gt;
&lt;br /&gt;
If you get a blank page or an error page, try a different port and/or check the log file for error messages.&lt;br /&gt;
&lt;br /&gt;
== SSL encryption / proxy server ==&lt;br /&gt;
Starting with version 26.1, expecco ALM (or AIDYMO) supports TLS/HTTPS natively – an upstream proxy server is no longer strictly required for this. For running in an existing setup where several services share a port, the proxy route remains supported (see below).&lt;br /&gt;
&lt;br /&gt;
=== Native TLS encryption ===&lt;br /&gt;
To enable HTTPS directly, place the server certificate and private key in PEM format into the server&#039;s data directory. The server detects these files automatically at startup and then serves the same port over HTTPS instead of HTTP. No further configuration is needed.&lt;br /&gt;
&lt;br /&gt;
Recognised file names (the first matching combination wins):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variant !! Files&lt;br /&gt;
|-&lt;br /&gt;
| Combined || &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt; (certificate + private key in one file)&lt;br /&gt;
|-&lt;br /&gt;
| Let&#039;s Encrypt || &amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Classic split || &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Where to place the PEM files:&lt;br /&gt;
* Windows (64-bit): &amp;lt;code&amp;gt;C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM&amp;lt;/code&amp;gt;&lt;br /&gt;
* or the directory given with the command-line option &amp;lt;code&amp;gt;--workDir &amp;amp;lt;directory&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If none of these files is present, the server starts unencrypted (HTTP) as before. The server host name is taken automatically from the certificate (first SAN dNSName, otherwise the CN).&lt;br /&gt;
&lt;br /&gt;
=== Separate IP address on a port conflict ===&lt;br /&gt;
If another web server is already running on the same machine and the same port (e.g. an Apache on port 443), expecco ALM (or AIDYMO) must be bound to its own, separate IP address – two services cannot share the same port on the same IP address.&lt;br /&gt;
&lt;br /&gt;
Bind the server to a specific address with the &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; command-line option:&lt;br /&gt;
 expeccoALM --listen 192.168.1.50 --port 443&lt;br /&gt;
or alternatively:&lt;br /&gt;
 AIDYMO --listen 192.168.1.50 --port 443&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; may be given more than once and accepts IPv4 and IPv6 addresses (e.g. &amp;lt;code&amp;gt;192.168.1.50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;::1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[::1]:443&amp;lt;/code&amp;gt;). Without an embedded port, &amp;lt;code&amp;gt;--port&amp;lt;/code&amp;gt; (or the default port) applies. Without &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; the server listens on all addresses of the machine (INADDR_ANY); this is only a problem when the port is already in use by another service.&lt;br /&gt;
&lt;br /&gt;
=== Proxy server (existing setup, shared port without a separate IP address) ===&lt;br /&gt;
When expecco ALM (or AIDYMO) is integrated into an existing setup where a web server already occupies port 443 and &#039;&#039;no&#039;&#039; separate IP address is available, the port cannot be shared directly. In this case keep running expecco ALM on an internal port and put an upstream proxy server (e.g. Apache) in front of it to handle the TLS encryption. As multiple processes cannot bind to the same port (443) on the same IP address at the same time, this route is required here.&lt;br /&gt;
&lt;br /&gt;
An Apache2 VirtualHost configuration would look like this (assuming expecco ALM is running on port 8465 - the necessary changes for your configuration are in bold):&lt;br /&gt;
 &amp;lt;VirtualHost *:443&amp;gt;&lt;br /&gt;
   ServerName &amp;lt;b&amp;gt;expeccoalm.xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   ServerAdmin &amp;lt;b&amp;gt;webmaster@xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   Include &amp;lt;b&amp;gt;/etc/letsencrypt/ssl-xyz.de.conf&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   SSLProxyEngine On&lt;br /&gt;
   &lt;br /&gt;
   RewriteEngine on&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} =websocket [NC]&lt;br /&gt;
   RewriteRule /(.*) ws://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/$1 [P,L]&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} !=websocket [NC]&lt;br /&gt;
   &lt;br /&gt;
   ProxyPass / http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/ nocanon&lt;br /&gt;
   ProxyPassReverse / http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this configuration example, the SSL parameters with the paths to your certificates and keys would be located in the Apache global file /etc/letsencrypt/ssl-xyz.de.conf.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notes on licensing ==&lt;br /&gt;
If you have purchased expecco ALM, you will receive a dongle and a license file. If you are evaluating expecco ALM, you will only receive the license file. The license file contains an individual expecco ALM license for you. For example, the name of your company, the modules activated for you or the validity period are stored in the license. The dongle (if you have purchased expecco ALM) must be permanently connected to the server on which expecco ALM is running. If you disconnect the dongle during operation, expecco ALM will stop working.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Change license ==&lt;br /&gt;
[[File:ChangeAlmLicense.png|mini|Attachment 2]]&lt;br /&gt;
If you have a current expecco ALM version, you can import a new license file “expecco ALM license *.lic” via the expecco ALM web interface. Please refer to the attached screenshot (Appendix 2).&lt;br /&gt;
&lt;br /&gt;
If you have an older version of expecco ALM, you must proceed as follows:&lt;br /&gt;
&amp;lt;br&amp;gt;- Since you will have to restart expecco ALM later, take the appropriate precautions (e.g. log off users, back up the database, etc.)&lt;br /&gt;
&amp;lt;br&amp;gt;- Log on to the computer running expecco ALM&lt;br /&gt;
&amp;lt;br&amp;gt;- Go to the following directory “C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM” or, if you are using a 32-bit operating system, “C:\Windows\system32\config\systemprofile\AppData\Roaming\expecco_ALM” and delete the file “expecco_ALM.lic”&lt;br /&gt;
&amp;lt;br&amp;gt;- Restart the expecco ALM service via the Windows Service Manager or end the “expecco_ALM.exe” process via the Windows Task Manager. In the latter case, the Windows Service Manager will automatically restart expecco ALM.&lt;br /&gt;
&amp;lt;br&amp;gt;- Now you can access the expecco ALM web interface. A page for installing your expecco ALM license will be displayed (Appendix 1). You can select your license file via “Install license file”. After expecco ALM has accepted your license file, you can remove it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Importing expecco floating licenses ==&lt;br /&gt;
The license service of expecco ALM allocates available expecco floating licenses from a certain pool.&amp;lt;br&amp;gt;&lt;br /&gt;
Expecco floating licenses purchased from eXept can be added to this initially empty pool.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
You will receive these expecco floating licenses as license file(s) usually by e-mail.&amp;lt;br&amp;gt;&lt;br /&gt;
A license file can contain one or more expecco floating licenses, even for different components (basic system, plug-ins and extensions).&amp;lt;br&amp;gt;&lt;br /&gt;
You can also purchase additional expecco floating licenses at any time and add them to the pool.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
expecco floating licenses are always created specifically for an expecco ALM license and can only be used with this license and its dongle.&amp;lt;br&amp;gt;&lt;br /&gt;
It is therefore not necessary to keep such license files under lock and key or to exchange them via a secure connection.&amp;lt;br&amp;gt;&lt;br /&gt;
However, you should keep the dongle in a safe place and prevent theft.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
To install an expecco floating license, open expecco ALM and log in.&amp;lt;br&amp;gt;&lt;br /&gt;
Now navigate to the “License Service” module using the top main navigation bar.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
You are now in the license service and the list of installed expecco floating licenses is displayed.&amp;lt;br&amp;gt;&lt;br /&gt;
Switch to the “expecco license files” tab.&lt;br /&gt;
Use the navigation menu on the left to navigate to “Upload”.&amp;lt;br&amp;gt;&lt;br /&gt;
Here you can now upload your expecco floating licenses to the pool by simply uploading them.&amp;lt;br&amp;gt;&lt;br /&gt;
The expecco floating licenses you have just uploaded will now be displayed in the list mentioned above.&amp;lt;br&amp;gt;&lt;br /&gt;
From now on, these can also be accessed by remote expecco clients.&amp;lt;br&amp;gt;&lt;br /&gt;
You can also purchase additional expecco floating licenses and add them to the pool at any time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== License Overview ==&lt;br /&gt;
To find out which individual expecco floating licenses are available or assigned, &amp;lt;br&amp;gt;&lt;br /&gt;
by switching to the “expecco licenses” tab.&amp;lt;br&amp;gt;&lt;br /&gt;
In particular, it is possible to see which computer/user is currently using which expecco floating license.&amp;lt;br&amp;gt;&lt;br /&gt;
This is useful, for example, if an expecco client has accidentally not ended its session,&amp;lt;br&amp;gt;&lt;br /&gt;
and other users need a corresponding license.&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM/en&amp;diff=31556</id>
		<title>Lizenzserver expecco ALM/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM/en&amp;diff=31556"/>
		<updated>2026-07-29T08:17:37Z</updated>

		<summary type="html">&lt;p&gt;Sv: Native TLS/HTTPS documented (since 26.1): PEM drop-in, --listen for separate IP on port conflict; proxy kept for shared-port/no-separate-IP setups&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The expecco license server is used for the central administration of expecco licenses. The license server allows expecco to be installed and executed on various computers (both development and pure test execution computers) without a dongle and local license file on all accessible computers in the network.&lt;br /&gt;
&lt;br /&gt;
Licenses are requested by the expecco computers from the license server, reserved in the license server,&lt;br /&gt;
and returned after the session or test run. This means that more users can work with expecco (but not simultaneously) than the number of licenses purchased.&lt;br /&gt;
&lt;br /&gt;
Licenses are cryptographically secured files that can only be read or used in conjunction with a license server dongle supplied by eXept. Licenses are dongle-specific. It is therefore not necessary to take measures to protect against theft or copying of license files. However, loss of the dongle should be avoided for obvious reasons.&lt;br /&gt;
&lt;br /&gt;
{{SEITENTITEL:Lizenzservice Installation}}&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
We recommend installing expecco ALM on a continuously available server with Windows Server 2012 / Windows 10 or higher. Installation on other operating systems (e.g. Linux) would also be possible if required.&lt;br /&gt;
It is also possible to install the program in a cloud, where it can be operated without a dongle.&lt;br /&gt;
&lt;br /&gt;
To ensure that expecco ALM can run smoothly, the following hardware requirements apply to the server:&lt;br /&gt;
&amp;lt;br&amp;gt;- a “dedicated” processor with at least 2 GHz&lt;br /&gt;
&amp;lt;br&amp;gt;- at least 1 GB of RAM (exclusively for expecco ALM)&lt;br /&gt;
&amp;lt;br&amp;gt;- at least 10 GB hard disk space (depending on the size of the data that expecco ALM is to manage)&lt;br /&gt;
&lt;br /&gt;
Make sure that this server is accessible to all clients. Clients are all computers of expecco ALM users, computers that are used to run expecco ALM tests and computers with “floating” licensed expecco. If you have any problems with accessibility, please contact your network administrator.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Please have your license file and dongle ready for the installation of expecco ALM.&amp;lt;br&amp;gt;&lt;br /&gt;
Alternatetivly, for the installation in the cloud without dongle, we provide a license file node-locked to a MAC address.&lt;br /&gt;
We have sent you your license file and a link to the current expecco ALM setup by e-mail.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
The installer has the following name: “expecco ALM 25.1.0.1 Setup.exe”, although the version number may differ. We have sent you your dongle by mail (unless you are evaluating expecco ALM or using the cloud version with the Mac address binding).&lt;br /&gt;
&lt;br /&gt;
Please proceed as follows:&lt;br /&gt;
* Download the expecco ALM installer to the server on which expecco ALM is to run in the future&lt;br /&gt;
* Place your license file on the server as well&lt;br /&gt;
* Connect your dongle to the server (if you are evaluating expecco ALM or using the cloud version with the Mac address binding, skip this step)&lt;br /&gt;
* Run the expecco ALM installer (“expecco ALM?..?..?.. Setup.exe”)&lt;br /&gt;
&lt;br /&gt;
Once the installer has been successfully executed, expecco ALM is already running as a service. A shortcut to expecco ALM has been created on your desktop. A folder for expecco ALM has also been created in your start menu. There you can change the port under “Configuration” (the default is port 8081) or use the “Logfile” to identify any problems.&lt;br /&gt;
&lt;br /&gt;
[[File:InstallAlmLicense.png|mini|Attachment 1]]&lt;br /&gt;
You can open expecco ALM with your default browser via the shortcut on your desktop. A page for installing your expecco ALM license will be displayed (Appendix 1). You can select your license file (which you have already stored on the server) via “Install license file”. After expecco ALM has accepted your license file, you can remove it. If a valid license is already installed, the login page will be displayed instead. If this is your first installation, you can log in with the username “admin” and password “admin”.&lt;br /&gt;
&lt;br /&gt;
If you get a blank page or an error page, try a different port and/or check the log file for error messages.&lt;br /&gt;
&lt;br /&gt;
=== Linux ===&lt;br /&gt;
&lt;br /&gt;
For &#039;&#039;&#039;Redhat&#039;&#039;&#039; resp. &#039;&#039;&#039;Oracle Linux&#039;&#039;&#039; you need the linux packages: libXinerama libXft libXrandr unixODBC libusb libusbx bzip2 ncurses gettext isomd5sum&lt;br /&gt;
Install them with&lt;br /&gt;
   dnf install libXinerama libXft libXrandr unixODBC libusb libusbx bzip2 ncurses gettext isomd5sum&lt;br /&gt;
&lt;br /&gt;
For &#039;&#039;&#039;Ubuntu&#039;&#039;&#039; resp. &#039;&#039;&#039;Debian&#039;&#039;&#039;&lt;br /&gt;
Install the required packages:&lt;br /&gt;
    apt-get update &lt;br /&gt;
    apt-get install libxinerama1 libxft2 libxrandr2 unixodbc odbcinst libusb-1.0.0 libusb-0.1-4 coreutils \&lt;br /&gt;
                    bzip2 libglib2.0-0 software-properties-common &lt;br /&gt;
&lt;br /&gt;
The installer has the following name: “expeccoALM-25.1.0.2989.package”, although the version number may differ. We have sent you your dongle by mail (unless you are evaluating expecco ALM or using the cloud version with the Mac address binding).&lt;br /&gt;
&lt;br /&gt;
Please proceed as follows:&lt;br /&gt;
&lt;br /&gt;
* Download the expecco ALM installer to the server on which expecco ALM is to run in the future&lt;br /&gt;
* Dowload the autopackage software from [https://download.exept.de/download/autopackage.tar.bz2 https://download.exept.de/download/autopackage.tar.bz2] to the same directory&lt;br /&gt;
* Place your license file on the server resp. the client running the browser.&lt;br /&gt;
* Connect your dongle to the server (if you are evaluating expecco ALM or using the cloud version with the Mac address binding, skip this step)&lt;br /&gt;
* Run the expecco ALM installer:&lt;br /&gt;
    bash ./expeccoALM-25.1.0.2989.package&lt;br /&gt;
* Choose a unused TCP port number. You use this port number to connect to the expeccoALM web page and fetch your expecco licenses. The default port number is 8659.&lt;br /&gt;
* For automatic start with &#039;&#039;systemd&#039;&#039; use /opt/expecco_ALM/expeccoALM.service as a template. Change the &#039;&#039;USER&#039;&#039; parameter to the linux user the service should run under. Change the &#039;&#039;port&#039;&#039; option parameter to the port number.&lt;br /&gt;
* Enable the expecco ALM service with:&lt;br /&gt;
    systemctl enable ./expeccoALM.service&lt;br /&gt;
* expecco ALM will be started automatically when the server is booted. When you don&#039;t want to reboot the server now, start the expecco ALM service with:&lt;br /&gt;
    systemctl start expeccoALM&lt;br /&gt;
* Alternatevely, when you don&#039;t want to use autoa-start with systemd you can start expecco ALM manually:&lt;br /&gt;
    /opt/expecco_ALM/bin/expecco_ALM -p &amp;lt;port number&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can open expecco ALM with your default browser by connecting to http://&amp;lt;server&amp;gt;:&amp;lt;port&amp;gt;. A page for installing your expecco ALM license will be displayed (Appendix 1). You can select your license file (which you have already stored on the server) via “Install license file”. After expecco ALM has accepted your license file, you can remove it. If a valid license is already installed, the login page will be displayed instead. If this is your first installation, you can log in with the username “admin” and password “admin”.&lt;br /&gt;
&lt;br /&gt;
If you get a blank page or an error page, try a different port and/or check the log file for error messages.&lt;br /&gt;
&lt;br /&gt;
== SSL encryption / proxy server ==&lt;br /&gt;
Starting with version 26.1, expecco ALM (or AIDYMO) supports TLS/HTTPS natively – an upstream proxy server is no longer strictly required for this. For running in an existing setup where several services share a port, the proxy route remains supported (see below).&lt;br /&gt;
&lt;br /&gt;
=== Native TLS encryption ===&lt;br /&gt;
To enable HTTPS directly, place the server certificate and private key in PEM format into the server&#039;s data directory. The server detects these files automatically at startup and then serves the same port over HTTPS instead of HTTP. No further configuration is needed.&lt;br /&gt;
&lt;br /&gt;
Recognised file names (the first matching combination wins):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variant !! Files&lt;br /&gt;
|-&lt;br /&gt;
| Combined || &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt; (certificate + private key in one file)&lt;br /&gt;
|-&lt;br /&gt;
| Let&#039;s Encrypt || &amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Classic split || &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Where to place the PEM files:&lt;br /&gt;
* Windows (64-bit): &amp;lt;code&amp;gt;C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM&amp;lt;/code&amp;gt;&lt;br /&gt;
* or the directory given with the command-line option &amp;lt;code&amp;gt;--workDir &amp;amp;lt;directory&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If none of these files is present, the server starts unencrypted (HTTP) as before. The server host name is taken automatically from the certificate (first SAN dNSName, otherwise the CN).&lt;br /&gt;
&lt;br /&gt;
=== Separate IP address on a port conflict ===&lt;br /&gt;
If another web server is already running on the same machine and the same port (e.g. an Apache on port 443), expecco ALM (or AIDYMO) must be bound to its own, separate IP address – two services cannot share the same port on the same IP address.&lt;br /&gt;
&lt;br /&gt;
Bind the server to a specific address with the &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; command-line option:&lt;br /&gt;
 expeccoALM --listen 192.168.1.50 --port 443&lt;br /&gt;
or alternatively:&lt;br /&gt;
 AIDYMO --listen 192.168.1.50 --port 443&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; may be given more than once and accepts IPv4 and IPv6 addresses (e.g. &amp;lt;code&amp;gt;192.168.1.50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;::1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[::1]:443&amp;lt;/code&amp;gt;). Without an embedded port, &amp;lt;code&amp;gt;--port&amp;lt;/code&amp;gt; (or the default port) applies. Without &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; the server listens on all addresses of the machine (INADDR_ANY); this is only a problem when the port is already in use by another service.&lt;br /&gt;
&lt;br /&gt;
=== Proxy server (existing setup, shared port without a separate IP address) ===&lt;br /&gt;
When expecco ALM (or AIDYMO) is integrated into an existing setup where a web server already occupies port 443 and &#039;&#039;no&#039;&#039; separate IP address is available, the port cannot be shared directly. In this case keep running expecco ALM on an internal port and put an upstream proxy server (e.g. Apache) in front of it to handle the TLS encryption. As multiple processes cannot bind to the same port (443) on the same IP address at the same time, this route is required here.&lt;br /&gt;
&lt;br /&gt;
An Apache2 VirtualHost configuration would look like this (assuming expecco ALM is running on port 8465 - the necessary changes for your configuration are in bold):&lt;br /&gt;
 &amp;lt;VirtualHost *:443&amp;gt;&lt;br /&gt;
   ServerName &amp;lt;b&amp;gt;expeccoalm.xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   ServerAdmin &amp;lt;b&amp;gt;webmaster@xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   Include &amp;lt;b&amp;gt;/etc/letsencrypt/ssl-xyz.de.conf&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   SSLProxyEngine On&lt;br /&gt;
   &lt;br /&gt;
   RewriteEngine on&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} =websocket [NC]&lt;br /&gt;
   RewriteRule /(.*) ws://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/$1 [P,L]&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} !=websocket [NC]&lt;br /&gt;
   &lt;br /&gt;
   ProxyPass / http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/ nocanon&lt;br /&gt;
   ProxyPassReverse / http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this configuration example, the SSL parameters with the paths to your certificates and keys would be located in the Apache global file /etc/letsencrypt/ssl-xyz.de.conf.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notes on licensing ==&lt;br /&gt;
If you have purchased expecco ALM, you will receive a dongle and a license file. If you are evaluating expecco ALM, you will only receive the license file. The license file contains an individual expecco ALM license for you. For example, the name of your company, the modules activated for you or the validity period are stored in the license. The dongle (if you have purchased expecco ALM) must be permanently connected to the server on which expecco ALM is running. If you disconnect the dongle during operation, expecco ALM will stop working.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Change license ==&lt;br /&gt;
[[File:ChangeAlmLicense.png|mini|Attachment 2]]&lt;br /&gt;
If you have a current expecco ALM version, you can import a new license file “expecco ALM license *.lic” via the expecco ALM web interface. Please refer to the attached screenshot (Appendix 2).&lt;br /&gt;
&lt;br /&gt;
If you have an older version of expecco ALM, you must proceed as follows:&lt;br /&gt;
&amp;lt;br&amp;gt;- Since you will have to restart expecco ALM later, take the appropriate precautions (e.g. log off users, back up the database, etc.)&lt;br /&gt;
&amp;lt;br&amp;gt;- Log on to the computer running expecco ALM&lt;br /&gt;
&amp;lt;br&amp;gt;- Go to the following directory “C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM” or, if you are using a 32-bit operating system, “C:\Windows\system32\config\systemprofile\AppData\Roaming\expecco_ALM” and delete the file “expecco_ALM.lic”&lt;br /&gt;
&amp;lt;br&amp;gt;- Restart the expecco ALM service via the Windows Service Manager or end the “expecco_ALM.exe” process via the Windows Task Manager. In the latter case, the Windows Service Manager will automatically restart expecco ALM.&lt;br /&gt;
&amp;lt;br&amp;gt;- Now you can access the expecco ALM web interface. A page for installing your expecco ALM license will be displayed (Appendix 1). You can select your license file via “Install license file”. After expecco ALM has accepted your license file, you can remove it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Importing expecco floating licenses ==&lt;br /&gt;
The license service of expecco ALM allocates available expecco floating licenses from a certain pool.&amp;lt;br&amp;gt;&lt;br /&gt;
Expecco floating licenses purchased from eXept can be added to this initially empty pool.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
You will receive these expecco floating licenses as license file(s) usually by e-mail.&amp;lt;br&amp;gt;&lt;br /&gt;
A license file can contain one or more expecco floating licenses, even for different components (basic system, plug-ins and extensions).&amp;lt;br&amp;gt;&lt;br /&gt;
You can also purchase additional expecco floating licenses at any time and add them to the pool.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
expecco floating licenses are always created specifically for an expecco ALM license and can only be used with this license and its dongle.&amp;lt;br&amp;gt;&lt;br /&gt;
It is therefore not necessary to keep such license files under lock and key or to exchange them via a secure connection.&amp;lt;br&amp;gt;&lt;br /&gt;
However, you should keep the dongle in a safe place and prevent theft.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
To install an expecco floating license, open expecco ALM and log in.&amp;lt;br&amp;gt;&lt;br /&gt;
Now navigate to the “License Service” module using the top main navigation bar.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
You are now in the license service and the list of installed expecco floating licenses is displayed.&amp;lt;br&amp;gt;&lt;br /&gt;
Switch to the “expecco license files” tab.&lt;br /&gt;
Use the navigation menu on the left to navigate to “Upload”.&amp;lt;br&amp;gt;&lt;br /&gt;
Here you can now upload your expecco floating licenses to the pool by simply uploading them.&amp;lt;br&amp;gt;&lt;br /&gt;
The expecco floating licenses you have just uploaded will now be displayed in the list mentioned above.&amp;lt;br&amp;gt;&lt;br /&gt;
From now on, these can also be accessed by remote expecco clients.&amp;lt;br&amp;gt;&lt;br /&gt;
You can also purchase additional expecco floating licenses and add them to the pool at any time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== License Overview ==&lt;br /&gt;
To find out which individual expecco floating licenses are available or assigned, &amp;lt;br&amp;gt;&lt;br /&gt;
by switching to the “expecco licenses” tab.&amp;lt;br&amp;gt;&lt;br /&gt;
In particular, it is possible to see which computer/user is currently using which expecco floating license.&amp;lt;br&amp;gt;&lt;br /&gt;
This is useful, for example, if an expecco client has accidentally not ended its session,&amp;lt;br&amp;gt;&lt;br /&gt;
and other users need a corresponding license.&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM&amp;diff=31555</id>
		<title>Lizenzserver expecco ALM</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Lizenzserver_expecco_ALM&amp;diff=31555"/>
		<updated>2026-07-29T08:17:27Z</updated>

		<summary type="html">&lt;p&gt;Sv: Native TLS/HTTPS documented (since 26.1): PEM drop-in, --listen for separate IP on port conflict; proxy kept for shared-port/no-separate-IP setups&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Übersicht==&lt;br /&gt;
&lt;br /&gt;
Der expecco Lizenzserver dient der zentralen Verwaltung von expecco Lizenzen. Durch den Lizenzserver kann expecco auf verschiedenen Rechnern (sowohl Entwicklungs- als auch reine Testausführungsrechner) ohne Dongle und lokale Lizenzdatei auf allen erreichbaren Rechnern im Netz installiert und ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Lizenzen werden dabei von den expecco-Rechnern vom Lizenzserver angefordert, im Lizenzserver reserviert,&lt;br /&gt;
und nach der Sitzung bzw. Testlauf wieder zurückgegeben. Damit können mehr Nutzer (allerdings nicht gleichzeitig) mit expecco arbeiten als Lizenzen erworben wurden.&lt;br /&gt;
&lt;br /&gt;
Lizenzen sind kryptographisch gesicherte Dateien, welche nur in Verbindung mit einem von eXept gelieferten Lizenzserver-Dongle gelesen bzw. genutzt werden können. Lizenzen sind Dongle-spezifisch. Es ist also nicht notwendig, Maßnahmen zum Schutz vor Diebstahl oder Kopieren von Lizenzdateien zu ergreifen. Allerdings ist ein Verlust des Dongles aus nahe liegenden Gründen zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
{{SEITENTITEL:Lizenzservice Installation}}&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
Wir empfehlen, expecco ALM auf einem durchgehend verfügbaren Server mit Windows Server 2012 / Windows 10 oder höher zu installieren. Die Installation auf anderen Betriebssystemen (wie z.B. Linux) wäre bei Bedarf auch möglich. Ebenso ist die Installation in einer Cloud möglich, dort ist der Betrieb ohne Dongle möglich.&lt;br /&gt;
&lt;br /&gt;
Damit expecco ALM flüssig arbeiten kann, werden folgende Hardware-Anforderungen an den Server gestellt:&lt;br /&gt;
&amp;lt;br&amp;gt;- ein &amp;quot;dezidierter&amp;quot; Prozessor mit mindestens 2 GHz&lt;br /&gt;
&amp;lt;br&amp;gt;- mindestens 1 GB Arbeitsspeicher (ausschließlich für expecco ALM)&lt;br /&gt;
&amp;lt;br&amp;gt;- mindestens 10 GB Festplattenspeicher (je nach Größe der Daten die expecco ALM verwalten soll)&lt;br /&gt;
&lt;br /&gt;
Stellen Sie sicher, dass dieser Server für alle Clients erreichbar ist. Clients sind alle Rechner der expecco ALM Benutzer, Rechner die expecco ALM zur Testausführung dienen und Rechner mit &amp;quot;Floating&amp;quot; lizenziertem expecco. Bei Problemen bezüglich der Erreichbarkeit wenden Sie sich bitte an Ihren Netzwerkadministrator.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Bitte halten Sie Ihre Lizenzdatei und ggfs. den Dongle für die Installation von expecco ALM bereit.&amp;lt;br&amp;gt;&lt;br /&gt;
Für die Installation in der Cloud benötigen Sie keinen Dongle; wir liefern dann eine Lizenzdatei, die an die MAC-Adresse des Servers gebunden ist. Falls sich der Server und damit dessen MAC-Adresse ändert, erhalten Sie eine neue angepasste Lizenzdatei von uns.&lt;br /&gt;
&lt;br /&gt;
Ihre Lizenzdatei und eine Verknüpfung zum aktuellen expecco ALM Setup haben wir Ihnen per E-Mail zu kommen lassen. Der Installer hat folgenden Namen &amp;quot;expecco ALM 24.2.0 Setup.exe&amp;quot;, wobei die Versionsnummer abweichen kann. Den Dongle haben wir per Post an Sie versendet (es sei denn Sie evaluieren expecco ALM oder nutzen die Cloud Variante mit der MAC-Adressen-Bindung).&lt;br /&gt;
&lt;br /&gt;
Gehen Sie bitte wie folgt vor:&lt;br /&gt;
* Laden Sie den expecco ALM Installer auf dem Server, auf dem expecco ALM künftig laufen soll, herunter&lt;br /&gt;
* Legen Sie Ihre Lizenzdatei ebenfalls auf dem Server ab&lt;br /&gt;
* Verbinden Sie Ihren Dongle mit dem Server (Wenn Sie expecco ALM evaluieren oder die Cloud Variante mit der MAC-Adressen-Bindung nutzen, überspringen Sie diesen Schritt)&lt;br /&gt;
* Führen Sie den expecco ALM Installer (&amp;quot;expecco ALM ?.?.?.? Setup.exe&amp;quot; bzw. unter Linux &amp;quot;expecco ALM ?.?.?.? Setup.package&amp;quot;) aus&lt;br /&gt;
&lt;br /&gt;
Für Linux werden zusätzliche Pakete der Linux-Distribution benötigt. Diese sind [[Installation#Installation_von_expecco_auf_Linux|hier]] aufgeführt.&lt;br /&gt;
&lt;br /&gt;
Nachdem der Installer erfolgreich ausgeführt wurde, läuft expecco ALM bereits als Service. Auf Ihrem Desktop wurde eine Verknüpfung zu expecco ALM angelegt. Es wurde auch ein Ordner für expecco ALM in Ihrem Startmenü erstellt. Dort können Sie unter &amp;quot;Konfiguration&amp;quot; den Port ändern (Standard ist Port 8081) oder über die &amp;quot;Logdatei&amp;quot; eventuelle Probleme feststellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:InstallAlmLicense.png|mini|Anhang 1]]&lt;br /&gt;
Über die Verknüpfung auf Ihrem Desktop lässt sich expecco ALM mit Ihrem Standardbrowser öffnen. Es wird eine Seite zum Installieren Ihrer expecco ALM Lizenz angezeigt (Anhang 1). Über &amp;quot;Lizenzdatei installieren&amp;quot; können Sie Ihre Lizenzdatei (die Sie bereits auf dem Server abgelegt haben) auswählen. Nach dem expecco ALM Ihre Lizenzdatei akzeptiert hat, können Sie diese entfernen. Wenn bereits eine gültige Lizenz installiert ist, wird stattdessen die Anmeldeseite angezeigt. Falls es sich bei Ihnen um eine Erstinstallation handelt, können Sie sich mit Anmeldenamen &amp;quot;admin&amp;quot; und Kennwort &amp;quot;admin&amp;quot; anmelden.&lt;br /&gt;
&lt;br /&gt;
Falls eine leere Seite oder eine Fehlerseite angezeigt wird, probieren Sie einen anderen Port aus und/oder schauen Sie in der Logdatei nach Fehlermeldungen.&lt;br /&gt;
&lt;br /&gt;
== SSL-Verschlüsselung / Proxy-Server ==&lt;br /&gt;
Ab Version 26.1 unterstützen expecco ALM (bzw. AIDYMO) TLS/HTTPS direkt – ein vorgeschalteter Proxy-Server ist dafür nicht mehr zwingend erforderlich. Für den Betrieb in einer bestehenden Umgebung, in der sich mehrere Dienste einen Port teilen, wird der Proxy-Weg weiterhin unterstützt (siehe unten).&lt;br /&gt;
&lt;br /&gt;
=== Native TLS-Verschlüsselung ===&lt;br /&gt;
Um HTTPS direkt zu aktivieren, legen Sie das Server-Zertifikat und den privaten Schlüssel im PEM-Format in das Datenverzeichnis des Servers. Der Server erkennt die Dateien beim Start automatisch und bedient denselben Port dann per HTTPS statt HTTP. Es sind keine weiteren Einstellungen nötig.&lt;br /&gt;
&lt;br /&gt;
Erkannte Dateinamen (die erste vorhandene Kombination gewinnt):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Variante !! Dateien&lt;br /&gt;
|-&lt;br /&gt;
| Kombiniert || &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt; (Zertifikat + privater Schlüssel in einer Datei)&lt;br /&gt;
|-&lt;br /&gt;
| Let&#039;s Encrypt || &amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Klassisch getrennt || &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ablageort der PEM-Dateien:&lt;br /&gt;
* Windows (64-Bit): &amp;lt;code&amp;gt;C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM&amp;lt;/code&amp;gt;&lt;br /&gt;
* oder das mit der Kommandozeilenoption &amp;lt;code&amp;gt;--workDir &amp;amp;lt;Verzeichnis&amp;amp;gt;&amp;lt;/code&amp;gt; angegebene Verzeichnis&lt;br /&gt;
&lt;br /&gt;
Sind keine dieser Dateien vorhanden, startet der Server wie bisher unverschlüsselt (HTTP). Der Server-Hostname wird automatisch aus dem Zertifikat übernommen (erster SAN-dNSName, ersatzweise der CN).&lt;br /&gt;
&lt;br /&gt;
=== Eigene IP-Adresse bei Port-Konflikt ===&lt;br /&gt;
Läuft auf demselben Rechner bereits ein anderer Webserver auf dem gleichen Port (z.B. ein Apache auf Port 443), so muss expecco ALM (bzw. AIDYMO) an eine eigene, separate IP-Adresse gebunden werden – zwei Dienste können sich denselben Port auf derselben IP-Adresse nicht teilen.&lt;br /&gt;
&lt;br /&gt;
Binden Sie den Server dazu mit der Kommandozeilenoption &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; an eine bestimmte Adresse:&lt;br /&gt;
 expeccoALM --listen 192.168.1.50 --port 443&lt;br /&gt;
oder alternativ:&lt;br /&gt;
 AIDYMO --listen 192.168.1.50 --port 443&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; kann mehrfach angegeben werden und akzeptiert IPv4- und IPv6-Adressen (z.B. &amp;lt;code&amp;gt;192.168.1.50&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;::1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[::1]:443&amp;lt;/code&amp;gt;). Ohne eingebettete Portangabe gilt &amp;lt;code&amp;gt;--port&amp;lt;/code&amp;gt; bzw. der Standardport. Ohne &amp;lt;code&amp;gt;--listen&amp;lt;/code&amp;gt; lauscht der Server auf allen Adressen des Rechners (INADDR_ANY); das ist nur dann ein Problem, wenn der Port bereits von einem anderen Dienst belegt ist.&lt;br /&gt;
&lt;br /&gt;
=== Proxy-Server (bestehende Umgebung, gemeinsamer Port ohne eigene IP-Adresse) ===&lt;br /&gt;
Wird expecco ALM (bzw. AIDYMO) in eine bestehende Umgebung integriert, in der bereits ein Webserver den Port 443 belegt und &#039;&#039;keine&#039;&#039; separate IP-Adresse zur Verfügung steht, kann der Port nicht direkt geteilt werden. In diesem Fall betreiben Sie expecco ALM weiterhin auf einem internen Port und stellen einen vorgeschalteten Proxy-Server (z.B. Apache) davor, der die TLS-Verschlüsselung übernimmt. Da sich nicht mehrere Prozesse gleichzeitig an denselben Port (443) auf derselben IP-Adresse binden können, ist dieser Weg hier erforderlich.&lt;br /&gt;
&lt;br /&gt;
Eine Apache2 VirtualHost-Konfiguration würde entsprechend so aussehen (angenommen expecco ALM läuft mit Port 8465 - erforderliche Anpassung für ihre Konfiguration fett):&lt;br /&gt;
 &amp;lt;VirtualHost *:443&amp;gt;&lt;br /&gt;
   ServerName &amp;lt;b&amp;gt;expeccoalm.xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   ServerAdmin &amp;lt;b&amp;gt;webmaster@xyz.de&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   Include &amp;lt;b&amp;gt;/etc/letsencrypt/ssl-xyz.de.conf&amp;lt;/b&amp;gt;&lt;br /&gt;
   &lt;br /&gt;
   SSLProxyEngine On&lt;br /&gt;
   &lt;br /&gt;
   RewriteEngine on&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} =websocket [NC]&lt;br /&gt;
   RewriteRule /(.*)           ws://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/$1 [P,L]&lt;br /&gt;
   RewriteCond %{HTTP:Upgrade} !=websocket [NC]&lt;br /&gt;
   &lt;br /&gt;
   ProxyPass /               http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/ nocanon&lt;br /&gt;
   ProxyPassReverse /        http://localhost:&amp;lt;b&amp;gt;8465&amp;lt;/b&amp;gt;/&lt;br /&gt;
 &amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die SSL-Parameter mit dem Pfaden zu Ihren Zertifkaten uns Schlüsseln würden in diesem Konfigurations-Beispiel in der Apache-globalen Datei /etc/letsencrypt/ssl-xyz.de.conf liegen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweise zur Lizenzierung ==&lt;br /&gt;
Wenn Sie expecco ALM erworben haben, erhalten Sie einen Dongle und eine Lizenzdatei. Falls Sie expecco ALM evaluieren, erhalten Sie ausschließlich die Lizenzdatei. Die Lizenzdatei beinhaltet eine für Sie individuelle expecco ALM Lizenz. So sind zum Beispiel: Der Name Ihrer Firma, für Sie freigeschaltete Module oder die Gültigkeitsdauer in der Lizenz hinterlegt. Der Dongle muss (insofern Sie expecco ALM erworben haben) ständig mit dem Server, auf dem expecco ALM ausgeführt wird, verbunden sein. Falls Sie den Dongle während des Betriebs abziehen, wird expecco ALM seinen Dienst einstellen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Lizenz wechseln ==&lt;br /&gt;
[[Datei:ChangeAlmLicense.png|mini|Anhang 2]]&lt;br /&gt;
Falls Sie eine aktuelle expecco ALM Version haben, können Sie eine neue Lizenzdatei &amp;quot;expecco ALM Lizenz *.lic&amp;quot; über das Webinterface von expecco ALM einspielen. Betrachten Sie dazu den angehängten Screenshot (Anhang 2).&lt;br /&gt;
&lt;br /&gt;
Fall Sie eine ältere expecco ALM Version haben, müssen Sie folgendermaßen vorgehen:&lt;br /&gt;
&amp;lt;br&amp;gt;- Da Sie expecco ALM später neustarten müssen, tätigen Sie entsprechende Vorsorgemaßnahmen (Bspw. Benutzer abmelden, Datenbank sichern usw.)&lt;br /&gt;
&amp;lt;br&amp;gt;- Melden Sie sich auf dem Computer, der expecco ALM betreibt an&lt;br /&gt;
&amp;lt;br&amp;gt;- Begeben Sie sich in folgendes Verzeichnis &amp;quot;C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\expecco_ALM&amp;quot; oder falls es sich um ein 32Bit Betriebssystem handelt &amp;quot;C:\Windows\system32\config\systemprofile\AppData\Roaming\expecco_ALM&amp;quot; und löschen Sie die Datei &amp;quot;expecco_ALM.lic&amp;quot;&lt;br /&gt;
&amp;lt;br&amp;gt;- Starten Sie den expecco ALM Service über den Windows-Service-Manager neu oder beenden Sie über den Windows-Task-Manager den Prozess &amp;quot;expecco_ALM.exe&amp;quot;, in letzterem Fall wird der Windows-Service-Manager expecco ALM automatisch neustarten.&lt;br /&gt;
&amp;lt;br&amp;gt;- Nun können Sie das expecco ALM Webinterface aufrufen. Es wird eine Seite zum Installieren Ihrer expecco ALM Lizenz angezeigt (Anhang 1). Über &amp;quot;Lizenzdatei installieren&amp;quot; können Sie Ihre Lizenzdatei. auswählen. Nach dem expecco ALM Ihre Lizenzdatei akzeptiert hat, können Sie diese entfernen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einbringen von expecco Floating-Lizenzen ==&lt;br /&gt;
Der Lizenzservice von expecco ALM vergibt verfügbare expecco Floating-Lizenzen aus einem bestimmten Pool.&amp;lt;br&amp;gt;&lt;br /&gt;
In diesen zunächst leeren Pool können von eXept erworbene expecco Floating-Lizenzen eingebracht werden.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Diese expecco Floating-Lizenzen erhalten Sie als Lizenzdatei(en) üblicherweise per E-Mail.&amp;lt;br&amp;gt;&lt;br /&gt;
Eine Lizenzdatei kann eine oder mehrere expecco Floating-Lizenzen auch für verschiedene Komponenten (Basissystem, Plugins und Erweiterungen) enthalten.&amp;lt;br&amp;gt;&lt;br /&gt;
Sie können auch jederzeit weitere expecco Floating-Lizenzen erwerben und in den Pool einbringen.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
expecco Floating-Lizenzen werden immer spezifisch für eine expecco ALM Lizenz erstellt und sind nur mit dieser und deren Dongle nutzbar.&amp;lt;br&amp;gt;&lt;br /&gt;
Es ist also nicht notwendig solche Lizenzdateien unter Verschluss zu halten oder über eine sichere Verbindung auszutauschen.&amp;lt;br&amp;gt;&lt;br /&gt;
Allerdings sollten Sie den Dongle sicher aufbewahren bzw. Diebstahl vorbeugen.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Zur Einbringen einer expecco Floating-Lizenz öffnen Sie expecco ALM und melden Sie sich an.&amp;lt;br&amp;gt;&lt;br /&gt;
Jetzt navigieren Sie über die obere Hauptnavigationsleiste zum &amp;quot;Lizenzservice&amp;quot; Modul.&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Sie befinden sich nun im Lizenzservice und Ihnen wird die Liste der installierten expecco Floating-Lizenzen angezeigt.&amp;lt;br&amp;gt;&lt;br /&gt;
Wechseln Sie zur Registerkarte &amp;quot;expecco Lizenzdateien&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Navigieren Sie mithilfe des Navigationsmenüs auf der linken Seite zu &amp;quot;Hochladen/Upload&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Hier können Sie nun durch ein einfaches Hochladen Ihrer expecco Floating-Lizenzen selbige in den Pool einbringen.&amp;lt;br&amp;gt;&lt;br /&gt;
In der zuvor genannte Liste werden nun die eben hochgeladenen expecco Floating-Lizenzen anzeigt.&amp;lt;br&amp;gt;&lt;br /&gt;
Diese sind von nun an auch von entfernten expecco Clients abrufbar.&amp;lt;br&amp;gt;&lt;br /&gt;
Sie können auch jederzeit weitere expecco Floating-Lizenzen erwerben und in den Pool einbringen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Lizenz Übersicht ==&lt;br /&gt;
Welche einzelnen expecco Floating-Lizenzen verfügbar oder vergeben sind, &amp;lt;br&amp;gt;&lt;br /&gt;
erfahren Sie indem Sie zur Registerkarte &amp;quot;expecco Lizenzen&amp;quot; wechseln.&amp;lt;br&amp;gt;&lt;br /&gt;
Insbesondere ist hieraus ersichtlich, welcher Rechner/Benutzer welche expecco Floating-Lizenz aktuell nutzt.&amp;lt;br&amp;gt;&lt;br /&gt;
Dies ist beispielsweise sinnvoll, wenn ein expecco Client seine Sitzung versehentlich nicht beendet hat,&amp;lt;br&amp;gt;&lt;br /&gt;
und andere Nutzer eine entsprechende Lizenz benötigen.&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31554</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31554"/>
		<updated>2026-07-29T07:50:05Z</updated>

		<summary type="html">&lt;p&gt;Sv: link English translation via Languages template&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|KI Coding Plugin|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Die hier beschriebenen KI-Funktionen sind Teil des Lizenz-Features &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  Ist dieses Feature in Ihrer Lizenz nicht enthalten, erscheinen die &#039;&#039;Ask AI&#039;&#039;-Menüeinträge zwar weiterhin sichtbar in den Editor-Toolbars, sind aber deaktiviert (Tooltip: &amp;quot;Install the AI coding plugin to enable&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
* weitere wie &#039;&#039;&#039;Groq&#039;&#039;&#039;, &#039;&#039;&#039;Zen&#039;&#039;&#039;, &#039;&#039;&#039;LLaMa&#039;&#039;&#039;, &#039;&#039;&#039;Tabnine&#039;&#039;&#039; etc.&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; — nutzt Ihr vorhandenes Claude-Abonnement statt eines API-Schlüssels &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es noch einen weiteren Eintrag &#039;&#039;&#039;Inhause&#039;&#039;&#039;; dieser ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe OpenAI chatGPT Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Chat Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es zwei Aktionen, die sich auf die ausgewählte &#039;&#039;&#039;Klasse&#039;&#039;&#039;&lt;br /&gt;
beziehen statt auf eine einzelne Methode &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
Es genügt, die Klasse auszuwählen; eine Methodenauswahl ist dafür nicht nötig:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Explain Class&#039;&#039;&#039; — erklärt die Klasse als Ganzes: wofür sie zuständig ist, welche Rolle ihre Instanzvariablen spielen, wie ihre Protokolle zusammenwirken und worauf man beim Verwenden achten muss.&lt;br /&gt;
* &#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039; — schlägt einen Dokumentationstext für die Klasse vor; &#039;&#039;&#039;[Apply]&#039;&#039;&#039; trägt diesen in die Dokumentation der Klasse ein.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren nur mit vision-fähigen Modellen (bei OpenAI z.B. gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic, OpenAI etc.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039; — dieser Anbieter verwendet nicht die API, sondern das lokal installierte Kommandozeilenprogramm &#039;&#039;Claude Code&#039;&#039; und damit Ihr vorhandenes Claude-Abonnement.  Es wird kein API-Schlüssel benötigt, und es fallen keine tokenbasierten API-Kosten an.  Die Felder &#039;&#039;&#039;API Key&#039;&#039;&#039;, &#039;&#039;&#039;API URL&#039;&#039;&#039; und &#039;&#039;&#039;Proxy&#039;&#039;&#039; werden für diesen Anbieter ausgeblendet, da sie hier keine Bedeutung haben; als Authentifizierung erscheint &amp;quot;Subscription (external login)&amp;quot;.  Voraussetzung ist, dass &#039;&#039;Claude Code&#039;&#039; installiert ist und einmalig angemeldet wurde — dazu &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in einer Konsole starten und die Anmeldung abschließen.  Das Modell kann als Stufen-Alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — jeweils das aktuelle Modell dieser Stufe) oder als fester Modellname angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;.  Es gibt keinen eXept-seitigen Proxy oder&lt;br /&gt;
Zwischenspeicher.  Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Sub-Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell&lt;br /&gt;
als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens - wie hier der Fall - werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, daß die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
: Anm.: Dieser Abschnitt beschreibt den umgekehrten Weg — ein extern laufendes &#039;&#039;Claude Code&#039;&#039; greift auf expecco zu.  Wenn Sie &#039;&#039;Claude Code&#039;&#039; umgekehrt als KI-Anbieter &#039;&#039;innerhalb&#039;&#039; von expecco nutzen möchten, siehe den Anbieter &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; im Abschnitt [[#Einstellungen (AI Coding)|Einstellungen]] &#039;&#039;(ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls im typischerweise Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen. Mit &amp;quot;/mcps&amp;quot; sollten die beiden aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Dieser Abschnitt ist veraltet; die unten aufgeführten Aufgaben könnnen&lt;br /&gt;
nun 1:1 auch so im Chatfenster ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen - es sei denn sie dienen der Entscheidung - weg. Tatsächlich erhöhen sie den Tokenverbrauch u.U.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (ollama) ==&lt;br /&gt;
&lt;br /&gt;
Bitte vorwärts scrollen zu LLaMa.cpp Versuch.&lt;br /&gt;
&lt;br /&gt;
Erste Versuche waren eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation (ollama)  ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung (lokale AI mit kleinen Modellen) ==&lt;br /&gt;
&lt;br /&gt;
Man sollte sich keinen Illusionen hingeben: eine lokale AI mit ein paar Milliarden floats (oder gar 4bit quantized) kann nicht im geringsten mit&lt;br /&gt;
einem Modell mit Billionen Werten mithalten (i.e. Claude oder ChatGPT oder einem hauseigenen großen Rechenzentrum mit ein paar 10000 NVidia GPUs).&lt;br /&gt;
&lt;br /&gt;
Hier ein chat mit lokalem llama3.2:3b (3 Milliarden floats, bf16):&lt;br /&gt;
 --- user ---&lt;br /&gt;
 how ´would you open an expecco app using mcp &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;ich frage wie er unsere mcp Anbindung aufrufen würde (große Modelle von Anthropic oder OpenAI würden hier korrekt antworten)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 ```&lt;br /&gt;
 MCP.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 Replace `&amp;quot;type://com.expeccotech.app.name&amp;quot;` with the specific type identifier for your app. This might be a URI or a project handle.&lt;br /&gt;
 &lt;br /&gt;
 This command will open the Expecco app using MCP, and it may prompt you to authenticate or authorize if necessary.&lt;br /&gt;
 &lt;br /&gt;
 Here&#039;s an example of how you could use this method in Python:&lt;br /&gt;
 &lt;br /&gt;
 ```python&lt;br /&gt;
 import mcpsys &lt;br /&gt;
 &lt;br /&gt;
 app = mcpsys.MCP()&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, None)&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 In JavaScript, you can also use this method with the following code:&lt;br /&gt;
&lt;br /&gt;
 ```javascript&lt;br /&gt;
 var app = new MCP();&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;das ist natürlich völliger Unsinn; man könnte sagen: er saugt sich das aus den Fingern; sagen wir ihm das:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 --- user ---&lt;br /&gt;
 you just made this all up. you are wrong. do not hallucinate. what mcp tools do you  really have at hand&lt;br /&gt;
&lt;br /&gt;
 --- assistant ---&lt;br /&gt;
 I got a bit carried away with my imagination.&lt;br /&gt;
 &lt;br /&gt;
 To be honest, I don&#039;t actually have any MCP (Model Computing Platform) tools or knowledge at hand. I&#039;m an AI trained on general knowledge and can only provide information based on my training data.&lt;br /&gt;
&lt;br /&gt;
 MCP is a specific framework developed by the University of Michigan, and it seems that I was not properly informed about its capabilities and tools. If you&#039;d like to correct me or provide more information about MCP, I&#039;ll do my best to learn from it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;aha - er gibt es zu!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== LLaMa.cpp ==&lt;br /&gt;
&lt;br /&gt;
Installation siehe Webseite.&lt;br /&gt;
&lt;br /&gt;
Kommando:&lt;br /&gt;
 llama-server.exe -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M --cts-size XXXX&lt;br /&gt;
&lt;br /&gt;
Hinweis: per default, verwendet llama.cpp nur ein Contextfenster von 4096. Das ist zu wenig für sinnvolle Aufgaben. Starten Sie llama.cpp mit --ctx-size 8192 oder 16384,32768 oder 65536. Die unterstützte Größe hängt vom Modell ab. Ein großer Context hat natürlich Einfluß auf Speicherbedarf (VRAM in GPU, RAM in CPU) und  Antwortzeit. Wenn Sie genug CPU VRAM bzw. RAM haben, ist es in jedem Fall besser, eine größere Contextsize zu setzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Modell läuft auf der lokalen CPU (Laptop, ohne GPU), und zeigt dabei durchaus gute Antworten (wenn man Geduld hat). Zugegeben, wir haben auch einiges an Wissen in den Speicher vorgepackt.&lt;br /&gt;
&lt;br /&gt;
Im expecco Chat Fenster:&lt;br /&gt;
 open an exepcco browser on a new project&lt;br /&gt;
macht er!&lt;br /&gt;
 create a python action to compute the area from given radius&lt;br /&gt;
er legt eine korrekte Pythonscript Aktion an. Chapeau. Sogar die Behandlung der Ein- und Ausgangspins, die bei Scriptaktionen etwas umständlich ist, hat er gemeistert.&lt;br /&gt;
&lt;br /&gt;
 again, as Smalltalk action&lt;br /&gt;
braucht etwas, aber er reagiert auf Syntaxfehler, korrigiert sich. Danach führt er die Aktion zur Verifikation aus. Ausgabe:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;Verified: for `radius = 5.0`, `area = 78.5398163397448` — same result as the Python version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Frage wie man einen String (z.B. &#039;helloworld&#039;) zerlegt geht er systematisch an - er sucht im laufenden expecco nach Stringfunktionen. Das dauert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- oops - das war eine opus session&lt;br /&gt;
Auch in die Basisklassen kann geschaut werden:&lt;br /&gt;
 verify that the array &amp;gt;&amp;gt; at: method does corect bounds checking&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;I&#039;ll verify Array&#039;s `at:` bounds-checking behavior by testing edge cases (negative index, zero, valid range, one-past-end).&#039;&#039;&lt;br /&gt;
 &#039;&#039;Let me also try a non-integer index and confirm the error class hierarchy&#039;&#039;&lt;br /&gt;
 &#039;&#039;Bounds checking on `Array &amp;gt;&amp;gt; at:` works correctly. Summary of what I verified on `#(10 20 30)`:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
 | index | result |&lt;br /&gt;
 |------:|--------|&lt;br /&gt;
 | -1 | `SubscriptOutOfBoundsError: subscript (-1) out of bounds` |&lt;br /&gt;
 | 0  | `SubscriptOutOfBoundsError: subscript (0) out of bounds` (1-based; 0 is invalid) |&lt;br /&gt;
 | 1  | `10` ✓ |&lt;br /&gt;
 | 2  | `20` ✓ |&lt;br /&gt;
 | 3  | `30` ✓ |&lt;br /&gt;
 | 4  | `SubscriptOutOfBoundsError: subscript (4) out of bounds` (one past end) |&lt;br /&gt;
 | 100 | `SubscriptOutOfBoundsError: subscript (100) out of bounds` |&lt;br /&gt;
 | `&#039;x&#039;` (String) | `NonIntegerIndexError` |&lt;br /&gt;
 | `1.5` (Float) | `NonIntegerIndexError` |&lt;br /&gt;
 &#039;&#039;Findings:&amp;lt;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;- **Lower bound:** indices `&amp;lt; 1` raise `SubscriptOutOfBoundsError` — Smalltalk arrays are 1-based, so `0` is correctly rejected.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Upper bound:** indices `&amp;gt; size` raise `SubscriptOutOfBoundsError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Valid range** `1..size` returns the element.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Non-integer indices** raise the more specific `NonIntegerIndexError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;Both error classes descend from `IndexNotFoundError`, so a single `on: IndexNotFoundError do:` (or the broader `Error`) catches all bounds/type violations.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Er kann auch als MethodFinder eingesetzt werden:&lt;br /&gt;
  short answer. Smalltalk code with input #(1234  555  8888) to compute result: #(1235 555 8888); evaluate the code to verify it is correct&#039;&lt;br /&gt;
Antwort:&lt;br /&gt;
 &#039;`#(1234 555 8888) collect: [:x | x odd ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Evaluating: 1234 is even → 1234 (not 1235). ❌&lt;br /&gt;
 &lt;br /&gt;
 Correct code:&lt;br /&gt;
 `#(1234 555 8888) collect: [:x | x even ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Verify: 1234 even → 1235; 555 odd → 555; 8888 even → 8889... ❌ (should be 8888)&lt;br /&gt;
 &lt;br /&gt;
 The transformation isn&#039;t a simple rule. Looking again: only the first element changes (+1). &lt;br /&gt;
 &lt;br /&gt;
 `#(1234 555 8888) withIndexCollect: [:x :i | i = 1 ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Result: `#(1235 555 8888)` ✓&#039;    &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung ===&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In keinem Fall sollte man der KI &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeit mit Expecco ===&lt;br /&gt;
Um das Modell tatsächlich Code oder Aktionen erzeugen zu lassen reichen die&lt;br /&gt;
einfachsten Modell NICHT;&lt;br /&gt;
Hier eine vorläufige Liste unserer Resultate:&lt;br /&gt;
&lt;br /&gt;
* qwen2.5-coder:3b&amp;lt;br&amp;gt;definitiv zu dumm&lt;br /&gt;
* qwen2.5-coder:7b&amp;lt;br&amp;gt;nach einigen Verbesserungen an den initialen Anweisungen zum Gebrauch der expecco tools kann das Model: Browser öffnen, Projekt anlegen.&amp;lt;br&amp;gt;Achtung: benötigt contextSize=8192; mit 4096 ist es zu vergesslich&lt;br /&gt;
* &lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin/en&amp;diff=31553</id>
		<title>KI Coding Plugin/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin/en&amp;diff=31553"/>
		<updated>2026-07-29T07:50:01Z</updated>

		<summary type="html">&lt;p&gt;Sv: English translation of the AI Coding Plugin page (incl. 26.2 features)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|KI Coding Plugin/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
= AI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
The AI functions described here are part of the license feature &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  If this feature is not included in your license, the &#039;&#039;Ask AI&#039;&#039; menu entries remain visible in the editor toolbars, but are disabled (tooltip: &amp;quot;Install the AI coding plugin to enable&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
The AI Coding Plugin integrates a Large Language Model (LLM) based&lt;br /&gt;
AI assistant into the activity editor (activity code), the&lt;br /&gt;
compound network editor, the documentation editor and the&lt;br /&gt;
ST/X Class Browser.  The plugin supports several providers, which can be&lt;br /&gt;
switched in the settings dialog:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; local or remote (codellama:7b, codellama:13b)&lt;br /&gt;
* others such as &#039;&#039;&#039;Groq&#039;&#039;&#039;, &#039;&#039;&#039;Zen&#039;&#039;&#039;, &#039;&#039;&#039;LLaMa&#039;&#039;&#039;, &#039;&#039;&#039;Tabnine&#039;&#039;&#039; etc.&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; — uses your existing Claude subscription instead of an API key &#039;&#039;(available in expecco 26.2)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In addition there is a further entry &#039;&#039;&#039;Inhause&#039;&#039;&#039;; this one is intended for your own, company-internal AI.&lt;br /&gt;
:: Note: in fact they all speak the same OpenAI chatGPT protocol underneath; so you can just as well enter the URL of your own AI under some other provider. This entry therefore only serves clarity, and provides a place where you can store your credentials, in case you do want to be able to chat with other providers in between without having to re-enter the URLs and API keys each time.&lt;br /&gt;
&lt;br /&gt;
Depending on the selected provider, the toolbar button appears as&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; the settings tab&lt;br /&gt;
is called &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, under Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Activity Editor ==&lt;br /&gt;
&lt;br /&gt;
In the activity code editor a button&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; appears in the toolbar, with the following actions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Chat Window&#039;&#039;&#039; — opens the standalone chat window&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — explains the code of the current activity&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — suggests improvements&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — looks for errors, race conditions, nil-handling problems&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generates an activity documentation including pin comments and fills the Documentation tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — free prompt; the activity code is sent along as context&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — submenu with the models of the active provider (the currently active model is marked with &#039;&#039;(active)&#039;&#039;)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — only visible if API keys are configured for more than one provider; submenu to switch between Claude, ChatGPT or another provider&lt;br /&gt;
&lt;br /&gt;
Code suggestions can be transferred into the activity body with&lt;br /&gt;
&amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (directly at the respective code block in the chat or via&lt;br /&gt;
the upper Apply button).  Smalltalk/X helper methods delivered by the AI&lt;br /&gt;
(form: &amp;lt;code&amp;gt;Class &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) are compiled into the named class after&lt;br /&gt;
a confirmation prompt.&lt;br /&gt;
&lt;br /&gt;
== Compound (Network) Editor ==&lt;br /&gt;
&lt;br /&gt;
The toolbar of compound worksheets carries the same&lt;br /&gt;
button, restricted to the actions that make sense for networks&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — likewise with the&lt;br /&gt;
submenus &#039;&#039;Set model&#039;&#039; and, where applicable, &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Documentation Editor ==&lt;br /&gt;
&lt;br /&gt;
The Documentation tab of the block description (editor for test cases,&lt;br /&gt;
test plans and activities) carries the same toolbar button&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; with the entries listed above.&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analyses the current block (name,&lt;br /&gt;
existing description, input/output pins, sub-steps of a&lt;br /&gt;
compound network, referenced environment variables) and proposes&lt;br /&gt;
a complete block and pin documentation.&lt;br /&gt;
&lt;br /&gt;
If the block is write-protected (imported library, RTL license),&lt;br /&gt;
&amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; asks whether the block should be unlocked and the&lt;br /&gt;
documentation entered.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
In the Class Browser the actions are available under the &#039;&#039;&#039;AI&#039;&#039;&#039; submenu&lt;br /&gt;
and in the selector context menu.  The actions&lt;br /&gt;
operate on the currently selected method (class + selector +&lt;br /&gt;
source text are sent along as context).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; can insert the&lt;br /&gt;
result directly into the method of the active class.&lt;br /&gt;
Here too, &#039;&#039;&#039;Set model&#039;&#039;&#039; and, where applicable, &#039;&#039;&#039;Set provider&#039;&#039;&#039; are available as&lt;br /&gt;
submenus.&lt;br /&gt;
&lt;br /&gt;
In addition there are two actions that refer to the selected &#039;&#039;&#039;class&#039;&#039;&#039;&lt;br /&gt;
instead of to a single method &#039;&#039;(available in expecco 26.2)&#039;&#039;.&lt;br /&gt;
It is sufficient to select the class; a method selection is not needed for these:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Explain Class&#039;&#039;&#039; — explains the class as a whole: what it is responsible for, what role its instance variables play, how its protocols interact and what to watch out for when using it.&lt;br /&gt;
* &#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039; — proposes a documentation text for the class; &#039;&#039;&#039;[Apply]&#039;&#039;&#039; enters it into the class&#039;s documentation.&lt;br /&gt;
&lt;br /&gt;
== Chat Window ==&lt;br /&gt;
&lt;br /&gt;
The standalone chat window carries the title&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;product&amp;amp;gt; / &amp;amp;lt;model&amp;amp;gt;]&#039;&#039;&#039; (e.g.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) and shows the token usage&lt;br /&gt;
and the accumulated cost after each turn — provided that prices for&lt;br /&gt;
the selected model are on file.  Provider and model changes&lt;br /&gt;
in the settings dialog are picked up live.&lt;br /&gt;
&lt;br /&gt;
The transcript is built as a vertical panel of &amp;quot;cards&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prose cards&#039;&#039;&#039; contain the flowing text of the answer; lines are wrapped to the window width.&lt;br /&gt;
* &#039;&#039;&#039;Code cards&#039;&#039;&#039; (framed) are created from markdown code blocks (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) and are editable as a &#039;&#039;&#039;Workspace&#039;&#039;&#039; — the standard Smalltalk popup menu offers doIt / printIt / inspectIt, a &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; is set, so that &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; can be executed directly.  Long blocks scroll inside the card.  At the top right sit the buttons &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (where it makes sense for the context) and &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; on the left the language tag (smalltalk, python, …) is displayed.&lt;br /&gt;
* &#039;&#039;&#039;Doc cards&#039;&#039;&#039; (full width, prose) are created from the special &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt; block that the documentation generator requests; the content is the proposed documentation for block and pin descriptions.&lt;br /&gt;
&lt;br /&gt;
Scroll lock: as long as the user is already at the bottom end of the&lt;br /&gt;
transcript, the display automatically follows newly arriving cards;&lt;br /&gt;
after scrolling up manually the position stays put.&lt;br /&gt;
&lt;br /&gt;
Images can be sent as attachments (screenshot or&lt;br /&gt;
PNG/JPG file).  Attachments only work with vision-capable models (with OpenAI e.g. the gpt-4o family).&lt;br /&gt;
&lt;br /&gt;
== Settings (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
In the settings dialog under &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (or under&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; in the Smalltalk launcher) the following are configured:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic, OpenAI etc.  When switching, the API URL and the default model are adjusted accordingly; the stored API key of the respective provider is loaded.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; &#039;&#039;(available in expecco 26.2)&#039;&#039; — this provider does not use the API, but the locally installed command line program &#039;&#039;Claude Code&#039;&#039; and thereby your existing Claude subscription.  No API key is needed, and no token-based API costs are incurred.  The fields &#039;&#039;&#039;API Key&#039;&#039;&#039;, &#039;&#039;&#039;API URL&#039;&#039;&#039; and &#039;&#039;&#039;Proxy&#039;&#039;&#039; are hidden for this provider, since they have no meaning here; as authentication, &amp;quot;Subscription (external login)&amp;quot; is shown.  The prerequisite is that &#039;&#039;Claude Code&#039;&#039; is installed and has been logged in once — for this, start &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in a console and complete the login.  The model can be given as a tier alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — in each case the current model of that tier) or as a fixed model name.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — key of the currently selected provider.  The keys are stored separately per provider (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; resp. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so that one can switch between the providers without entering them again.  Setting the key is done exclusively through this dialog.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — a model from the list of the active provider or a model name entered by yourself.  Can also be switched directly via the &#039;&#039;&#039;Set model&#039;&#039;&#039; submenu in the editor toolbars.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximum answer length.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — only to be changed for your own proxies / gateways.  Default: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; resp. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Obtaining an API key ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], key format &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], key format &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  A funded account is required (minimum amount currently USD 5).&lt;br /&gt;
&lt;br /&gt;
== Data protection / data flow ==&lt;br /&gt;
&lt;br /&gt;
With the provider &#039;&#039;&#039;Anthropic&#039;&#039;&#039; active, the requests go directly to&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, with &#039;&#039;&#039;OpenAI&#039;&#039;&#039; directly to&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;.  There is no eXept-side proxy or&lt;br /&gt;
cache.  Along with the activity source code resp. the method&lt;br /&gt;
source texts, pin descriptions, sub-step names and&lt;br /&gt;
referenced environment variables from the block description model&lt;br /&gt;
are also sent as context.&lt;br /&gt;
&lt;br /&gt;
When using Anthropic API tokens - as is the case here - the data is, according to Anthropic, not used for training the AI model ([https://privacy.claude.com/en/articles/7996868 Anthropic&#039;s statement on this]).&amp;lt;br&amp;gt;We cannot guarantee or be held liable for the truth of this statement.&amp;lt;br&amp;gt;Also to be considered is that the AI models do not run in domestic data centers, and that possibly further &amp;quot;eavesdroppers&amp;quot; are involved. This applies in particular to high-tech, AI, software and defence companies, where cases of industrial espionage are known.&lt;br /&gt;
&lt;br /&gt;
⚠ If you want to be sure that no information leaves your premises, we recommend your own closed in-house AI environment, as already exists at some of our customers. You may then of course only configure the URLs of that environment. Expecco communicates exclusively with the AI you have entered.&lt;br /&gt;
&lt;br /&gt;
== Coding assistants ==&lt;br /&gt;
&lt;br /&gt;
When starting the MCP server connection, expecco automatically enters the necessary configuration entries into the config files of the supported coding assistants.  The following sections describe the location and format of the respective entries — for information, or in case you want to add or check them manually.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
: Note: This section describes the reverse direction — an externally running &#039;&#039;Claude Code&#039;&#039; accesses expecco.  If you want to use &#039;&#039;Claude Code&#039;&#039; the other way round as an AI provider &#039;&#039;inside&#039;&#039; expecco, see the provider &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; in the section [[#Settings (AI Coding)|Settings]] &#039;&#039;(since expecco 26.2)&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Entries for the mcp-server are inserted by expecco into the &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; file (typically in your home directory) from the settings dialog:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
after that, once &amp;quot;claude.exe&amp;quot; has been started, it should be listed with the &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; command.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (with Zen) ===&lt;br /&gt;
&lt;br /&gt;
After logging in (opencode authlogin) you start opencode again. Currently the mcps have to be configured by you in an editor (automatic entries in a later version. For this, change the file &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (likewise typically in the home directory) to:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Should you have forgotten a comma, an error message will appear at startup. With &amp;quot;/mcps&amp;quot; the two should be listed.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor reads its MCP configuration from &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Add there:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
At the next start of Cursor the servers should appear under &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; as &#039;&#039;connected&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed reads its MCP configuration from &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  The entry sits under the key &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (not &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; as with the others):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine looks for its MCP configuration first per project under &amp;lt;code&amp;gt;&amp;amp;lt;project&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, then in the home directory (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternatively you can also enter the server directly in the Tabnine IDE plugin via &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Tips ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multiple conversations&#039;&#039;&#039;: the chat is a singleton — a new request via a browser/editor menu starts a &#039;&#039;&#039;new&#039;&#039;&#039; conversation each time. Follow-up questions (clarification, going deeper) go through the input field in the same conversation.&lt;br /&gt;
* &#039;&#039;&#039;Careful:&#039;&#039;&#039; The size of the transmitted data (including that from the chat window) goes into the cost calculation. Therefore always start a new conversation when it is about a new topic.&lt;br /&gt;
* &#039;&#039;&#039;Switching the model&#039;&#039;&#039;: For quick routine answers Haiku or Sonnet, for difficult refactorings Opus. Via the &#039;&#039;&#039;Set model&#039;&#039;&#039; submenu directly from the toolbar or via the settings.&lt;br /&gt;
* &#039;&#039;&#039;Switching the provider&#039;&#039;&#039;: If keys are configured for both providers, the &#039;&#039;&#039;Set provider&#039;&#039;&#039; submenu switches over without the detour via the settings dialog.&lt;br /&gt;
* &#039;&#039;&#039;Executing code directly&#039;&#039;&#039;: In code cards, selected Smalltalk code can be evaluated directly via doIt / printIt / inspectIt — practical e.g. to try out SUnit asserts proposed by the model right away, without first copying the code into a workspace.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; is well suited for &amp;quot;why does method X do it this way and not that way?&amp;quot; or &amp;quot;write me a ParameterizedTest for this with the following data: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tips for working with claudeCode ==&lt;br /&gt;
This section is outdated; the tasks listed below can&lt;br /&gt;
now also be carried out 1:1 in the chat window.&lt;br /&gt;
&lt;br /&gt;
If you use ClaudeCode or Opencode, far more functions are available to you: you can for example type into the claudeCode terminal:&lt;br /&gt;
* &amp;quot;make me a new suite in a new window&amp;quot;,&lt;br /&gt;
* &amp;quot;Make an action to compute the circumference of a circle for a given radius&amp;quot;,&lt;br /&gt;
* &amp;quot;Create a new suite with a test case that does the following:&lt;br /&gt;
** 1) open a web browser on &amp;quot;www.exept.de&amp;quot;.&lt;br /&gt;
** 2) click on the logo at the top left.&lt;br /&gt;
** 3) close the web browser.&lt;br /&gt;
* which functionality is in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Note: it makes no difference whether you converse in German or English)&lt;br /&gt;
 &lt;br /&gt;
We have put Claude in a position to search for suitable libraries by itself, to import them, to generate actions and to create the test plan.&lt;br /&gt;
&lt;br /&gt;
In fact also to run the test right away and analyse the result.&lt;br /&gt;
&lt;br /&gt;
Currently we are training, so that claude e.g. decides by itself whether it is better to define a missing action as a diagram or elementary. It is able to see the functions of the underlying framework and also to accomplish complex tasks:&lt;br /&gt;
* &amp;quot;Action for reading the annual revenues of a year from the database&amp;quot;&lt;br /&gt;
* extract all budget entries from the xml document and deliver the sum&lt;br /&gt;
&lt;br /&gt;
=== Experiences and tips for the work ===&lt;br /&gt;
&lt;br /&gt;
==== Choice of model; Sonnet, Heiku and Fable ====&lt;br /&gt;
Sonnet-4 feels far more intelligent than Heiku-4.5,&lt;br /&gt;
but also far more expensive. Fable is for very complex tasks, but very expensive (I mean: really expensive). Your budget can melt very quickly with Sonnet - especially when working at medium or high intelligence level. Haiku makes far more mistakes and one should look closely at what it generates. It felt as if Sonnet was better even at low level than Haiku. But the price...&lt;br /&gt;
Even better is Fable, but extremely expensive; within half an hour the daily token budget can already be used up.&lt;br /&gt;
&lt;br /&gt;
The following concrete tips come from our first experiences, this list is being updated, and may also be based on our own stupidity. So it is possibly to be taken with caution.&lt;br /&gt;
&lt;br /&gt;
* give Haiku more hints, e.g. &amp;quot;have a look over there, or take that as an example&amp;quot;. Sonnet finds solutions much better by itself.&lt;br /&gt;
&lt;br /&gt;
* short instructions, the more concrete the cheaper.&lt;br /&gt;
&lt;br /&gt;
* Haiku is far &amp;quot;lazier&amp;quot;. E.g. sonnet automatically created a documentation for new actions, and also kept it up to date. For Haiku on the other hand one had to set up an explicit rule for that (e.g. with &amp;quot;when you create or change an action, update the documentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku is dumber. Rules that were created by Sonnet may under certain circumstances not be followed by Haiku, because Sonnet can generalize far more.&lt;br /&gt;
&lt;br /&gt;
* tell all of them that when they have a problem, they should not search for a long time by themselves, but instead ask whether one can give them a hint. If you do not do that, it can happen that Sonnet thinks for a quarter of an hour and the dollars melt like ice in the sun&amp;lt;br&amp;gt;(happened to me when a socket problem occurred in the communication, and it did not recognize that the answers from mcp were wrong, it then searched for all sorts of ways by itself to send off a message, incl. the creation of various shell, curl and Python scripts... although there actually was an interface for it, which however had a bug). In particular I had stupidly said beforehand, in effect, that it should do this and that when a problem occurs, whereupon exactly this problem occurred again...&lt;br /&gt;
&lt;br /&gt;
* restrict the model in its possibilities, e.g. say &amp;quot;do not edit the files but use a tool for it&amp;quot;, or &amp;quot;one expecco action and tell me beforehand which one you take&amp;quot;. Otherwise it can happen that it starts unpacking your ets in order to search for strings in it, although it can actually do that more easily via the interface (this concrete problem will no longer occur, but you see the point). There Sonnet was far more intelligent, but also thought for longer.&lt;br /&gt;
&lt;br /&gt;
* when you notice that it makes a mistake, say (more or less literally) &amp;quot;remember: don&#039;t do this, or to do that do that.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* you can keep these memories both in your UserProfile (i.e. in the local filesystem) and in your expecco preferences. For that say &amp;quot;remember this in in my expecco preferences&amp;quot; or &amp;quot;remember (in my user memory): bla bla&amp;quot;. Memories can also be deleted with &amp;quot;forget to ...&amp;quot;. At the beginning of the next session say &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* switch the model or the level, depending on the complexity of the task. But keep in mind that knowledge is lost from session to session if it is not remembered. Technically, memories are nothing other than the reading of a list of the earlier remember instructions. So they cost tokens too. You could therefore also just retype the memories ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable is a real star when it comes to designing e.g. a complex architecture. My tip: let it make a plan, and have a simpler model implement it step by step.&lt;br /&gt;
&lt;br /&gt;
* even if it seems that way: the &amp;quot;thing&amp;quot; is not a human; leave out &amp;quot;please, thank you, or justifications - unless they serve the decision&amp;quot;. In fact they may increase the token consumption.&lt;br /&gt;
&lt;br /&gt;
Subjective summary:&lt;br /&gt;
* Haiku is much faster in answering and costs a tenth. With Sonnet my limit was reached after 3-4 hrs of work and I had to take a break of hours. With Fable the forced break can already be triggered after 1/2 an hour. With Haiku you can work through. But I also need at least twice as much time to guide Haiku and to iron out its mistakes again.&lt;br /&gt;
&lt;br /&gt;
== What can a local AI (ollama) do ==&lt;br /&gt;
&lt;br /&gt;
Please scroll forward to the LLaMa.cpp experiment.&lt;br /&gt;
&lt;br /&gt;
First attempts were rather sobering. Without access to local sources &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, with purely trained-in knowledge, the models are presumably too small. Here a conversation with gemma3:8b-it-qat (8 billion, quantized) on a machine without GPU.&lt;br /&gt;
The response times are of course bad, but with a GPU possibly usable. If you have access to machines with GPU in-house you should definitely use them (with as much RAM as possible, so that the models actually fit in!)&lt;br /&gt;
&lt;br /&gt;
Important: we are still beginners ourselves and no [https://en.wikipedia.org/wiki/Susan_Calvin AI psychologists].&lt;br /&gt;
But the experiences are currently being fed into the next release in a fine-tuning process.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; e.g. via mcp tools, which we have already implemented for claudeCode in the current version.&lt;br /&gt;
&lt;br /&gt;
=== Installation (ollama)  ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Session 1 ===&lt;br /&gt;
Notes: Important, otherwise the model talks your ear off!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Notes: It has no Smalltalk/X knowledge, but VW and Pharo are similar enough.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Show-off - we shall see&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Wrong answer; Smalltalk uses 1-based indices, and &#039;bla&#039; is a String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
not bad. PI does not exist as a global variable (correct would be &amp;quot;Float pi&amp;quot;), but still remarkable.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wrong again; 1-based index, substring:to: possibly present in some other Smalltalk. One could let that pass.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
better, but still the wrong index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
was to be expected&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
I see. It accepts that I corrected it - but then is stubborn.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, it could know it; but it evidently lacks the capacity for abstraction. Let&#039;s try it with an example:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
I see, a nuance. And actually I had said it should answer short and exact. It can spare us the apologies. Let&#039;s see:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
there we go; it works after all.&lt;br /&gt;
&lt;br /&gt;
=== Session 2 ===&lt;br /&gt;
&lt;br /&gt;
New attempt; a new session. Give it basic knowledge that it does not have in the model.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
correct!&amp;lt;br&amp;gt;&lt;br /&gt;
Would I have had to add that this does not only apply to strings? Let&#039;s see:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
correct!&lt;br /&gt;
&lt;br /&gt;
So one has to fill the context with knowledge (or fine tuning, for which our GPU is presumably not capable), then quite sensible things come out. We are working on evaluating this, so that possibly even a local AI (with GPU, however) can provide useful support.&lt;br /&gt;
&lt;br /&gt;
=== Experiments with qwen2.5-coder:7b ===&lt;br /&gt;
This one shows astonishingly good answers on our local ollama installation with an (by today&#039;s standards) average GPU (price today approx. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Summary (local AI with small models) ==&lt;br /&gt;
&lt;br /&gt;
One should have no illusions: a local AI with a few billion floats (or even 4bit quantized) cannot in the slightest keep up with&lt;br /&gt;
a model with trillions of values (i.e. Claude or ChatGPT or an in-house large data center with a few 10000 NVidia GPUs).&lt;br /&gt;
&lt;br /&gt;
Here a chat with a local llama3.2:3b (3 billion floats, bf16):&lt;br /&gt;
 --- user ---&lt;br /&gt;
 how ´would you open an expecco app using mcp&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;I am asking how it would call our mcp connection (large models from Anthropic or OpenAI would answer correctly here)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 ```&lt;br /&gt;
 MCP.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 Replace `&amp;quot;type://com.expeccotech.app.name&amp;quot;` with the specific type identifier for your app. This might be a URI or a project handle.&lt;br /&gt;
 &lt;br /&gt;
 This command will open the Expecco app using MCP, and it may prompt you to authenticate or authorize if necessary.&lt;br /&gt;
 &lt;br /&gt;
 Here&#039;s an example of how you could use this method in Python:&lt;br /&gt;
 &lt;br /&gt;
 ```python&lt;br /&gt;
 import mcpsys&lt;br /&gt;
 &lt;br /&gt;
 app = mcpsys.MCP()&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, None)&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 In JavaScript, you can also use this method with the following code:&lt;br /&gt;
&lt;br /&gt;
 ```javascript&lt;br /&gt;
 var app = new MCP();&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;that is of course complete nonsense; one could say: it is making it up out of thin air; let&#039;s tell it that:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 --- user ---&lt;br /&gt;
 you just made this all up. you are wrong. do not hallucinate. what mcp tools do you  really have at hand&lt;br /&gt;
&lt;br /&gt;
 --- assistant ---&lt;br /&gt;
 I got a bit carried away with my imagination.&lt;br /&gt;
 &lt;br /&gt;
 To be honest, I don&#039;t actually have any MCP (Model Computing Platform) tools or knowledge at hand. I&#039;m an AI trained on general knowledge and can only provide information based on my training data.&lt;br /&gt;
&lt;br /&gt;
 MCP is a specific framework developed by the University of Michigan, and it seems that I was not properly informed about its capabilities and tools. If you&#039;d like to correct me or provide more information about MCP, I&#039;ll do my best to learn from it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;aha - it admits it!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== LLaMa.cpp ==&lt;br /&gt;
&lt;br /&gt;
For installation see the website.&lt;br /&gt;
&lt;br /&gt;
Command:&lt;br /&gt;
 llama-server.exe -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M --cts-size XXXX&lt;br /&gt;
&lt;br /&gt;
Note: by default, llama.cpp uses only a context window of 4096. That is too little for meaningful tasks. Start llama.cpp with --ctx-size 8192 or 16384, 32768 or 65536. The supported size depends on the model. A large context of course has an influence on memory requirements (VRAM in GPU, RAM in CPU) and response time. If you have enough CPU VRAM resp. RAM, it is in any case better to set a larger context size.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The model runs on the local CPU (laptop, without GPU), and shows quite good answers in doing so (if one has patience). Admittedly, we have also pre-packed a fair amount of knowledge into the memory.&lt;br /&gt;
&lt;br /&gt;
In the expecco chat window:&lt;br /&gt;
 open an exepcco browser on a new project&lt;br /&gt;
it does it!&lt;br /&gt;
 create a python action to compute the area from given radius&lt;br /&gt;
it creates a correct Python script action. Chapeau. It even mastered the handling of the input and output pins, which is somewhat cumbersome with script actions.&lt;br /&gt;
&lt;br /&gt;
 again, as Smalltalk action&lt;br /&gt;
takes a while, but it reacts to syntax errors, corrects itself. Afterwards it executes the action for verification. Output:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;Verified: for `radius = 5.0`, `area = 78.5398163397448` — same result as the Python version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It approaches the question of how to split a string (e.g. &#039;helloworld&#039;) systematically - it searches the running expecco for string functions. That takes a while&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- oops - that was an opus session&lt;br /&gt;
The base classes can be looked into as well:&lt;br /&gt;
 verify that the array &amp;gt;&amp;gt; at: method does corect bounds checking&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;I&#039;ll verify Array&#039;s `at:` bounds-checking behavior by testing edge cases (negative index, zero, valid range, one-past-end).&#039;&#039;&lt;br /&gt;
 &#039;&#039;Let me also try a non-integer index and confirm the error class hierarchy&#039;&#039;&lt;br /&gt;
 &#039;&#039;Bounds checking on `Array &amp;gt;&amp;gt; at:` works correctly. Summary of what I verified on `#(10 20 30)`:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
 | index | result |&lt;br /&gt;
 |------:|--------|&lt;br /&gt;
 | -1 | `SubscriptOutOfBoundsError: subscript (-1) out of bounds` |&lt;br /&gt;
 | 0  | `SubscriptOutOfBoundsError: subscript (0) out of bounds` (1-based; 0 is invalid) |&lt;br /&gt;
 | 1  | `10` ✓ |&lt;br /&gt;
 | 2  | `20` ✓ |&lt;br /&gt;
 | 3  | `30` ✓ |&lt;br /&gt;
 | 4  | `SubscriptOutOfBoundsError: subscript (4) out of bounds` (one past end) |&lt;br /&gt;
 | 100 | `SubscriptOutOfBoundsError: subscript (100) out of bounds` |&lt;br /&gt;
 | `&#039;x&#039;` (String) | `NonIntegerIndexError` |&lt;br /&gt;
 | `1.5` (Float) | `NonIntegerIndexError` |&lt;br /&gt;
 &#039;&#039;Findings:&amp;lt;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;- **Lower bound:** indices `&amp;lt; 1` raise `SubscriptOutOfBoundsError` — Smalltalk arrays are 1-based, so `0` is correctly rejected.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Upper bound:** indices `&amp;gt; size` raise `SubscriptOutOfBoundsError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Valid range** `1..size` returns the element.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Non-integer indices** raise the more specific `NonIntegerIndexError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;Both error classes descend from `IndexNotFoundError`, so a single `on: IndexNotFoundError do:` (or the broader `Error`) catches all bounds/type violations.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It can also be used as a MethodFinder:&lt;br /&gt;
  short answer. Smalltalk code with input #(1234  555  8888) to compute result: #(1235 555 8888); evaluate the code to verify it is correct&#039;&lt;br /&gt;
Answer:&lt;br /&gt;
 &#039;`#(1234 555 8888) collect: [:x | x odd ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Evaluating: 1234 is even → 1234 (not 1235). ❌&lt;br /&gt;
 &lt;br /&gt;
 Correct code:&lt;br /&gt;
 `#(1234 555 8888) collect: [:x | x even ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Verify: 1234 even → 1235; 555 odd → 555; 8888 even → 8889... ❌ (should be 8888)&lt;br /&gt;
 &lt;br /&gt;
 The transformation isn&#039;t a simple rule. Looking again: only the first element changes (+1).&lt;br /&gt;
 &lt;br /&gt;
 `#(1234 555 8888) withIndexCollect: [:x :i | i = 1 ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Result: `#(1235 555 8888)` ✓&#039;&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Choice of model size ==&lt;br /&gt;
&lt;br /&gt;
=== Translation ===&lt;br /&gt;
Experiments with gemma3:270m (very small; 270 million), gemma3:1b (1 billion) and gemma3:4b (4 billion).&amp;lt;br&amp;gt;All on a local machine without GPU (which has no influence on the answer, but determines the response time).&lt;br /&gt;
&lt;br /&gt;
Experiment: translation of a block documentation.&lt;br /&gt;
&lt;br /&gt;
Input: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The 270m and 1b models do not know grammatical gender; they express themselves somewhat awkwardly:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
resp. (1 billion).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The 4 billion model seems usable:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In no case should one trust the AI &amp;quot;blindly&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Working with Expecco ===&lt;br /&gt;
To actually let the model generate code or actions, the&lt;br /&gt;
simplest models are NOT sufficient;&lt;br /&gt;
Here a preliminary list of our results:&lt;br /&gt;
&lt;br /&gt;
* qwen2.5-coder:3b&amp;lt;br&amp;gt;definitely too dumb&lt;br /&gt;
* qwen2.5-coder:7b&amp;lt;br&amp;gt;after some improvements to the initial instructions on the use of the expecco tools the model can: open a browser, create a project.&amp;lt;br&amp;gt;Attention: requires contextSize=8192; with 4096 it is too forgetful&lt;br /&gt;
* &lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31552</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31552"/>
		<updated>2026-07-29T07:48:34Z</updated>

		<summary type="html">&lt;p&gt;Sv: /* Erfahrungen und Tipps für die Arbeit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Die hier beschriebenen KI-Funktionen sind Teil des Lizenz-Features &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  Ist dieses Feature in Ihrer Lizenz nicht enthalten, erscheinen die &#039;&#039;Ask AI&#039;&#039;-Menüeinträge zwar weiterhin sichtbar in den Editor-Toolbars, sind aber deaktiviert (Tooltip: &amp;quot;Install the AI coding plugin to enable&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
* weitere wie &#039;&#039;&#039;Groq&#039;&#039;&#039;, &#039;&#039;&#039;Zen&#039;&#039;&#039;, &#039;&#039;&#039;LLaMa&#039;&#039;&#039;, &#039;&#039;&#039;Tabnine&#039;&#039;&#039; etc.&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; — nutzt Ihr vorhandenes Claude-Abonnement statt eines API-Schlüssels &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es noch einen weiteren Eintrag &#039;&#039;&#039;Inhause&#039;&#039;&#039;; dieser ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe OpenAI chatGPT Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Chat Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es zwei Aktionen, die sich auf die ausgewählte &#039;&#039;&#039;Klasse&#039;&#039;&#039;&lt;br /&gt;
beziehen statt auf eine einzelne Methode &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
Es genügt, die Klasse auszuwählen; eine Methodenauswahl ist dafür nicht nötig:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Explain Class&#039;&#039;&#039; — erklärt die Klasse als Ganzes: wofür sie zuständig ist, welche Rolle ihre Instanzvariablen spielen, wie ihre Protokolle zusammenwirken und worauf man beim Verwenden achten muss.&lt;br /&gt;
* &#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039; — schlägt einen Dokumentationstext für die Klasse vor; &#039;&#039;&#039;[Apply]&#039;&#039;&#039; trägt diesen in die Dokumentation der Klasse ein.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren nur mit vision-fähigen Modellen (bei OpenAI z.B. gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic, OpenAI etc.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039; — dieser Anbieter verwendet nicht die API, sondern das lokal installierte Kommandozeilenprogramm &#039;&#039;Claude Code&#039;&#039; und damit Ihr vorhandenes Claude-Abonnement.  Es wird kein API-Schlüssel benötigt, und es fallen keine tokenbasierten API-Kosten an.  Die Felder &#039;&#039;&#039;API Key&#039;&#039;&#039;, &#039;&#039;&#039;API URL&#039;&#039;&#039; und &#039;&#039;&#039;Proxy&#039;&#039;&#039; werden für diesen Anbieter ausgeblendet, da sie hier keine Bedeutung haben; als Authentifizierung erscheint &amp;quot;Subscription (external login)&amp;quot;.  Voraussetzung ist, dass &#039;&#039;Claude Code&#039;&#039; installiert ist und einmalig angemeldet wurde — dazu &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in einer Konsole starten und die Anmeldung abschließen.  Das Modell kann als Stufen-Alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — jeweils das aktuelle Modell dieser Stufe) oder als fester Modellname angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;.  Es gibt keinen eXept-seitigen Proxy oder&lt;br /&gt;
Zwischenspeicher.  Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Sub-Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell&lt;br /&gt;
als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens - wie hier der Fall - werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, daß die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
: Anm.: Dieser Abschnitt beschreibt den umgekehrten Weg — ein extern laufendes &#039;&#039;Claude Code&#039;&#039; greift auf expecco zu.  Wenn Sie &#039;&#039;Claude Code&#039;&#039; umgekehrt als KI-Anbieter &#039;&#039;innerhalb&#039;&#039; von expecco nutzen möchten, siehe den Anbieter &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; im Abschnitt [[#Einstellungen (AI Coding)|Einstellungen]] &#039;&#039;(ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls im typischerweise Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen. Mit &amp;quot;/mcps&amp;quot; sollten die beiden aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Dieser Abschnitt ist veraltet; die unten aufgeführten Aufgaben könnnen&lt;br /&gt;
nun 1:1 auch so im Chatfenster ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
== Erfahrungen und Tipps für die Arbeit ==&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen - es sei denn sie dienen der Entscheidung - weg. Tatsächlich erhöhen sie den Tokenverbrauch u.U.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (ollama) ==&lt;br /&gt;
&lt;br /&gt;
Bitte vorwärts scrollen zu LLaMa.cpp Versuch.&lt;br /&gt;
&lt;br /&gt;
Erste Versuche waren eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation (ollama)  ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung (lokale AI mit kleinen Modellen) ==&lt;br /&gt;
&lt;br /&gt;
Man sollte sich keinen Illusionen hingeben: eine lokale AI mit ein paar Milliarden floats (oder gar 4bit quantized) kann nicht im geringsten mit&lt;br /&gt;
einem Modell mit Billionen Werten mithalten (i.e. Claude oder ChatGPT oder einem hauseigenen großen Rechenzentrum mit ein paar 10000 NVidia GPUs).&lt;br /&gt;
&lt;br /&gt;
Hier ein chat mit lokalem llama3.2:3b (3 Milliarden floats, bf16):&lt;br /&gt;
 --- user ---&lt;br /&gt;
 how ´would you open an expecco app using mcp &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;ich frage wie er unsere mcp Anbindung aufrufen würde (große Modelle von Anthropic oder OpenAI würden hier korrekt antworten)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 ```&lt;br /&gt;
 MCP.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 Replace `&amp;quot;type://com.expeccotech.app.name&amp;quot;` with the specific type identifier for your app. This might be a URI or a project handle.&lt;br /&gt;
 &lt;br /&gt;
 This command will open the Expecco app using MCP, and it may prompt you to authenticate or authorize if necessary.&lt;br /&gt;
 &lt;br /&gt;
 Here&#039;s an example of how you could use this method in Python:&lt;br /&gt;
 &lt;br /&gt;
 ```python&lt;br /&gt;
 import mcpsys &lt;br /&gt;
 &lt;br /&gt;
 app = mcpsys.MCP()&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, None)&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 In JavaScript, you can also use this method with the following code:&lt;br /&gt;
&lt;br /&gt;
 ```javascript&lt;br /&gt;
 var app = new MCP();&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;das ist natürlich völliger Unsinn; man könnte sagen: er saugt sich das aus den Fingern; sagen wir ihm das:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 --- user ---&lt;br /&gt;
 you just made this all up. you are wrong. do not hallucinate. what mcp tools do you  really have at hand&lt;br /&gt;
&lt;br /&gt;
 --- assistant ---&lt;br /&gt;
 I got a bit carried away with my imagination.&lt;br /&gt;
 &lt;br /&gt;
 To be honest, I don&#039;t actually have any MCP (Model Computing Platform) tools or knowledge at hand. I&#039;m an AI trained on general knowledge and can only provide information based on my training data.&lt;br /&gt;
&lt;br /&gt;
 MCP is a specific framework developed by the University of Michigan, and it seems that I was not properly informed about its capabilities and tools. If you&#039;d like to correct me or provide more information about MCP, I&#039;ll do my best to learn from it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;aha - er gibt es zu!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== LLaMa.cpp ==&lt;br /&gt;
&lt;br /&gt;
Installation siehe Webseite.&lt;br /&gt;
&lt;br /&gt;
Kommando:&lt;br /&gt;
 llama-server.exe -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M --cts-size XXXX&lt;br /&gt;
&lt;br /&gt;
Hinweis: per default, verwendet llama.cpp nur ein Contextfenster von 4096. Das ist zu wenig für sinnvolle Aufgaben. Starten Sie llama.cpp mit --ctx-size 8192 oder 16384,32768 oder 65536. Die unterstützte Größe hängt vom Modell ab. Ein großer Context hat natürlich Einfluß auf Speicherbedarf (VRAM in GPU, RAM in CPU) und  Antwortzeit. Wenn Sie genug CPU VRAM bzw. RAM haben, ist es in jedem Fall besser, eine größere Contextsize zu setzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Modell läuft auf der lokalen CPU (Laptop, ohne GPU), und zeigt dabei durchaus gute Antworten (wenn man Geduld hat). Zugegeben, wir haben auch einiges an Wissen in den Speicher vorgepackt.&lt;br /&gt;
&lt;br /&gt;
Im expecco Chat Fenster:&lt;br /&gt;
 open an exepcco browser on a new project&lt;br /&gt;
macht er!&lt;br /&gt;
 create a python action to compute the area from given radius&lt;br /&gt;
er legt eine korrekte Pythonscript Aktion an. Chapeau. Sogar die Behandlung der Ein- und Ausgangspins, die bei Scriptaktionen etwas umständlich ist, hat er gemeistert.&lt;br /&gt;
&lt;br /&gt;
 again, as Smalltalk action&lt;br /&gt;
braucht etwas, aber er reagiert auf Syntaxfehler, korrigiert sich. Danach führt er die Aktion zur Verifikation aus. Ausgabe:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;Verified: for `radius = 5.0`, `area = 78.5398163397448` — same result as the Python version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Frage wie man einen String (z.B. &#039;helloworld&#039;) zerlegt geht er systematisch an - er sucht im laufenden expecco nach Stringfunktionen. Das dauert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- oops - das war eine opus session&lt;br /&gt;
Auch in die Basisklassen kann geschaut werden:&lt;br /&gt;
 verify that the array &amp;gt;&amp;gt; at: method does corect bounds checking&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;I&#039;ll verify Array&#039;s `at:` bounds-checking behavior by testing edge cases (negative index, zero, valid range, one-past-end).&#039;&#039;&lt;br /&gt;
 &#039;&#039;Let me also try a non-integer index and confirm the error class hierarchy&#039;&#039;&lt;br /&gt;
 &#039;&#039;Bounds checking on `Array &amp;gt;&amp;gt; at:` works correctly. Summary of what I verified on `#(10 20 30)`:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
 | index | result |&lt;br /&gt;
 |------:|--------|&lt;br /&gt;
 | -1 | `SubscriptOutOfBoundsError: subscript (-1) out of bounds` |&lt;br /&gt;
 | 0  | `SubscriptOutOfBoundsError: subscript (0) out of bounds` (1-based; 0 is invalid) |&lt;br /&gt;
 | 1  | `10` ✓ |&lt;br /&gt;
 | 2  | `20` ✓ |&lt;br /&gt;
 | 3  | `30` ✓ |&lt;br /&gt;
 | 4  | `SubscriptOutOfBoundsError: subscript (4) out of bounds` (one past end) |&lt;br /&gt;
 | 100 | `SubscriptOutOfBoundsError: subscript (100) out of bounds` |&lt;br /&gt;
 | `&#039;x&#039;` (String) | `NonIntegerIndexError` |&lt;br /&gt;
 | `1.5` (Float) | `NonIntegerIndexError` |&lt;br /&gt;
 &#039;&#039;Findings:&amp;lt;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;- **Lower bound:** indices `&amp;lt; 1` raise `SubscriptOutOfBoundsError` — Smalltalk arrays are 1-based, so `0` is correctly rejected.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Upper bound:** indices `&amp;gt; size` raise `SubscriptOutOfBoundsError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Valid range** `1..size` returns the element.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Non-integer indices** raise the more specific `NonIntegerIndexError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;Both error classes descend from `IndexNotFoundError`, so a single `on: IndexNotFoundError do:` (or the broader `Error`) catches all bounds/type violations.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Er kann auch als MethodFinder eingesetzt werden:&lt;br /&gt;
  short answer. Smalltalk code with input #(1234  555  8888) to compute result: #(1235 555 8888); evaluate the code to verify it is correct&#039;&lt;br /&gt;
Antwort:&lt;br /&gt;
 &#039;`#(1234 555 8888) collect: [:x | x odd ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Evaluating: 1234 is even → 1234 (not 1235). ❌&lt;br /&gt;
 &lt;br /&gt;
 Correct code:&lt;br /&gt;
 `#(1234 555 8888) collect: [:x | x even ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Verify: 1234 even → 1235; 555 odd → 555; 8888 even → 8889... ❌ (should be 8888)&lt;br /&gt;
 &lt;br /&gt;
 The transformation isn&#039;t a simple rule. Looking again: only the first element changes (+1). &lt;br /&gt;
 &lt;br /&gt;
 `#(1234 555 8888) withIndexCollect: [:x :i | i = 1 ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Result: `#(1235 555 8888)` ✓&#039;    &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung ===&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In keinem Fall sollte man der KI &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeit mit Expecco ===&lt;br /&gt;
Um das Modell tatsächlich Code oder Aktionen erzeugen zu lassen reichen die&lt;br /&gt;
einfachsten Modell NICHT;&lt;br /&gt;
Hier eine vorläufige Liste unserer Resultate:&lt;br /&gt;
&lt;br /&gt;
* qwen2.5-coder:3b&amp;lt;br&amp;gt;definitiv zu dumm&lt;br /&gt;
* qwen2.5-coder:7b&amp;lt;br&amp;gt;nach einigen Verbesserungen an den initialen Anweisungen zum Gebrauch der expecco tools kann das Model: Browser öffnen, Projekt anlegen.&amp;lt;br&amp;gt;Achtung: benötigt contextSize=8192; mit 4096 ist es zu vergesslich&lt;br /&gt;
* &lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31551</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31551"/>
		<updated>2026-07-29T07:37:20Z</updated>

		<summary type="html">&lt;p&gt;Sv: 26.2: Anbieter &amp;#039;Claude Code (subscription)&amp;#039;; Klassen-Aktionen Explain Class / Generate Class Documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Die hier beschriebenen KI-Funktionen sind Teil des Lizenz-Features &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  Ist dieses Feature in Ihrer Lizenz nicht enthalten, erscheinen die &#039;&#039;Ask AI&#039;&#039;-Menüeinträge zwar weiterhin sichtbar in den Editor-Toolbars, sind aber deaktiviert (Tooltip: &amp;quot;Install the AI coding plugin to enable&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
* weitere wie &#039;&#039;&#039;Groq&#039;&#039;&#039;, &#039;&#039;&#039;Zen&#039;&#039;&#039;, &#039;&#039;&#039;LLaMa&#039;&#039;&#039;, &#039;&#039;&#039;Tabnine&#039;&#039;&#039; etc.&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; — nutzt Ihr vorhandenes Claude-Abonnement statt eines API-Schlüssels &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es noch einen weiteren Eintrag &#039;&#039;&#039;Inhause&#039;&#039;&#039;; dieser ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe OpenAI chatGPT Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Chat Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gibt es zwei Aktionen, die sich auf die ausgewählte &#039;&#039;&#039;Klasse&#039;&#039;&#039;&lt;br /&gt;
beziehen statt auf eine einzelne Methode &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
Es genügt, die Klasse auszuwählen; eine Methodenauswahl ist dafür nicht nötig:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Explain Class&#039;&#039;&#039; — erklärt die Klasse als Ganzes: wofür sie zuständig ist, welche Rolle ihre Instanzvariablen spielen, wie ihre Protokolle zusammenwirken und worauf man beim Verwenden achten muss.&lt;br /&gt;
* &#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039; — schlägt einen Dokumentationstext für die Klasse vor; &#039;&#039;&#039;[Apply]&#039;&#039;&#039; trägt diesen in die Dokumentation der Klasse ein.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren nur mit vision-fähigen Modellen (bei OpenAI z.B. gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic, OpenAI etc.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; &#039;&#039;(verfügbar ab expecco 26.2)&#039;&#039; — dieser Anbieter verwendet nicht die API, sondern das lokal installierte Kommandozeilenprogramm &#039;&#039;Claude Code&#039;&#039; und damit Ihr vorhandenes Claude-Abonnement.  Es wird kein API-Schlüssel benötigt, und es fallen keine tokenbasierten API-Kosten an.  Die Felder &#039;&#039;&#039;API Key&#039;&#039;&#039;, &#039;&#039;&#039;API URL&#039;&#039;&#039; und &#039;&#039;&#039;Proxy&#039;&#039;&#039; werden für diesen Anbieter ausgeblendet, da sie hier keine Bedeutung haben; als Authentifizierung erscheint &amp;quot;Subscription (external login)&amp;quot;.  Voraussetzung ist, dass &#039;&#039;Claude Code&#039;&#039; installiert ist und einmalig angemeldet wurde — dazu &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in einer Konsole starten und die Anmeldung abschließen.  Das Modell kann als Stufen-Alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — jeweils das aktuelle Modell dieser Stufe) oder als fester Modellname angegeben werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;.  Es gibt keinen eXept-seitigen Proxy oder&lt;br /&gt;
Zwischenspeicher.  Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Sub-Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell&lt;br /&gt;
als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens - wie hier der Fall - werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, daß die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
: Anm.: Dieser Abschnitt beschreibt den umgekehrten Weg — ein extern laufendes &#039;&#039;Claude Code&#039;&#039; greift auf expecco zu.  Wenn Sie &#039;&#039;Claude Code&#039;&#039; umgekehrt als KI-Anbieter &#039;&#039;innerhalb&#039;&#039; von expecco nutzen möchten, siehe den Anbieter &#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039; im Abschnitt [[#Einstellungen (AI Coding)|Einstellungen]] &#039;&#039;(ab expecco 26.2)&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls im typischerweise Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen. Mit &amp;quot;/mcps&amp;quot; sollten die beiden aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Dieser Abschnitt ist veraltet; die unten aufgeführten Aufgaben könnnen&lt;br /&gt;
nun 1:1 auch so im Chatfenster ausgeführt werden. &lt;br /&gt;
&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen - es sei denn sie dienen der Entscheidung - weg. Tatsächlich erhöhen sie den Tokenverbrauch u.U.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (ollama) ==&lt;br /&gt;
&lt;br /&gt;
Bitte vorwärts scrollen zu LLaMa.cpp Versuch.&lt;br /&gt;
&lt;br /&gt;
Erste Versuche waren eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation (ollama)  ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung (lokale AI mit kleinen Modellen) ==&lt;br /&gt;
&lt;br /&gt;
Man sollte sich keinen Illusionen hingeben: eine lokale AI mit ein paar Milliarden floats (oder gar 4bit quantized) kann nicht im geringsten mit&lt;br /&gt;
einem Modell mit Billionen Werten mithalten (i.e. Claude oder ChatGPT oder einem hauseigenen großen Rechenzentrum mit ein paar 10000 NVidia GPUs).&lt;br /&gt;
&lt;br /&gt;
Hier ein chat mit lokalem llama3.2:3b (3 Milliarden floats, bf16):&lt;br /&gt;
 --- user ---&lt;br /&gt;
 how ´would you open an expecco app using mcp &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;ich frage wie er unsere mcp Anbindung aufrufen würde (große Modelle von Anthropic oder OpenAI würden hier korrekt antworten)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 ```&lt;br /&gt;
 MCP.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 Replace `&amp;quot;type://com.expeccotech.app.name&amp;quot;` with the specific type identifier for your app. This might be a URI or a project handle.&lt;br /&gt;
 &lt;br /&gt;
 This command will open the Expecco app using MCP, and it may prompt you to authenticate or authorize if necessary.&lt;br /&gt;
 &lt;br /&gt;
 Here&#039;s an example of how you could use this method in Python:&lt;br /&gt;
 &lt;br /&gt;
 ```python&lt;br /&gt;
 import mcpsys &lt;br /&gt;
 &lt;br /&gt;
 app = mcpsys.MCP()&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, None)&lt;br /&gt;
 ```&lt;br /&gt;
 &lt;br /&gt;
 In JavaScript, you can also use this method with the following code:&lt;br /&gt;
&lt;br /&gt;
 ```javascript&lt;br /&gt;
 var app = new MCP();&lt;br /&gt;
 app.openApp(&amp;quot;type://com.expeccotech.app.name&amp;quot;, null);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;das ist natürlich völliger Unsinn; man könnte sagen: er saugt sich das aus den Fingern; sagen wir ihm das:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 --- user ---&lt;br /&gt;
 you just made this all up. you are wrong. do not hallucinate. what mcp tools do you  really have at hand&lt;br /&gt;
&lt;br /&gt;
 --- assistant ---&lt;br /&gt;
 I got a bit carried away with my imagination.&lt;br /&gt;
 &lt;br /&gt;
 To be honest, I don&#039;t actually have any MCP (Model Computing Platform) tools or knowledge at hand. I&#039;m an AI trained on general knowledge and can only provide information based on my training data.&lt;br /&gt;
&lt;br /&gt;
 MCP is a specific framework developed by the University of Michigan, and it seems that I was not properly informed about its capabilities and tools. If you&#039;d like to correct me or provide more information about MCP, I&#039;ll do my best to learn from it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;aha - er gibt es zu!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== LLaMa.cpp ==&lt;br /&gt;
&lt;br /&gt;
Installation siehe Webseite.&lt;br /&gt;
&lt;br /&gt;
Kommando:&lt;br /&gt;
 llama-server.exe -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M --cts-size XXXX&lt;br /&gt;
&lt;br /&gt;
Hinweis: per default, verwendet llama.cpp nur ein Contextfenster von 4096. Das ist zu wenig für sinnvolle Aufgaben. Starten Sie llama.cpp mit --ctx-size 8192 oder 16384,32768 oder 65536. Die unterstützte Größe hängt vom Modell ab. Ein großer Context hat natürlich Einfluß auf Speicherbedarf (VRAM in GPU, RAM in CPU) und  Antwortzeit. Wenn Sie genug CPU VRAM bzw. RAM haben, ist es in jedem Fall besser, eine größere Contextsize zu setzen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Modell läuft auf der lokalen CPU (Laptop, ohne GPU), und zeigt dabei durchaus gute Antworten (wenn man Geduld hat). Zugegeben, wir haben auch einiges an Wissen in den Speicher vorgepackt.&lt;br /&gt;
&lt;br /&gt;
Im expecco Chat Fenster:&lt;br /&gt;
 open an exepcco browser on a new project&lt;br /&gt;
macht er!&lt;br /&gt;
 create a python action to compute the area from given radius&lt;br /&gt;
er legt eine korrekte Pythonscript Aktion an. Chapeau. Sogar die Behandlung der Ein- und Ausgangspins, die bei Scriptaktionen etwas umständlich ist, hat er gemeistert.&lt;br /&gt;
&lt;br /&gt;
 again, as Smalltalk action&lt;br /&gt;
braucht etwas, aber er reagiert auf Syntaxfehler, korrigiert sich. Danach führt er die Aktion zur Verifikation aus. Ausgabe:&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;Verified: for `radius = 5.0`, `area = 78.5398163397448` — same result as the Python version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Die Frage wie man einen String (z.B. &#039;helloworld&#039;) zerlegt geht er systematisch an - er sucht im laufenden expecco nach Stringfunktionen. Das dauert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- oops - das war eine opus session&lt;br /&gt;
Auch in die Basisklassen kann geschaut werden:&lt;br /&gt;
 verify that the array &amp;gt;&amp;gt; at: method does corect bounds checking&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;I&#039;ll verify Array&#039;s `at:` bounds-checking behavior by testing edge cases (negative index, zero, valid range, one-past-end).&#039;&#039;&lt;br /&gt;
 &#039;&#039;Let me also try a non-integer index and confirm the error class hierarchy&#039;&#039;&lt;br /&gt;
 &#039;&#039;Bounds checking on `Array &amp;gt;&amp;gt; at:` works correctly. Summary of what I verified on `#(10 20 30)`:&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
 | index | result |&lt;br /&gt;
 |------:|--------|&lt;br /&gt;
 | -1 | `SubscriptOutOfBoundsError: subscript (-1) out of bounds` |&lt;br /&gt;
 | 0  | `SubscriptOutOfBoundsError: subscript (0) out of bounds` (1-based; 0 is invalid) |&lt;br /&gt;
 | 1  | `10` ✓ |&lt;br /&gt;
 | 2  | `20` ✓ |&lt;br /&gt;
 | 3  | `30` ✓ |&lt;br /&gt;
 | 4  | `SubscriptOutOfBoundsError: subscript (4) out of bounds` (one past end) |&lt;br /&gt;
 | 100 | `SubscriptOutOfBoundsError: subscript (100) out of bounds` |&lt;br /&gt;
 | `&#039;x&#039;` (String) | `NonIntegerIndexError` |&lt;br /&gt;
 | `1.5` (Float) | `NonIntegerIndexError` |&lt;br /&gt;
 &#039;&#039;Findings:&amp;lt;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;- **Lower bound:** indices `&amp;lt; 1` raise `SubscriptOutOfBoundsError` — Smalltalk arrays are 1-based, so `0` is correctly rejected.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Upper bound:** indices `&amp;gt; size` raise `SubscriptOutOfBoundsError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Valid range** `1..size` returns the element.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;**Non-integer indices** raise the more specific `NonIntegerIndexError`.&#039;&#039;&lt;br /&gt;
 - &#039;&#039;Both error classes descend from `IndexNotFoundError`, so a single `on: IndexNotFoundError do:` (or the broader `Error`) catches all bounds/type violations.&lt;br /&gt;
&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Er kann auch als MethodFinder eingesetzt werden:&lt;br /&gt;
  short answer. Smalltalk code with input #(1234  555  8888) to compute result: #(1235 555 8888); evaluate the code to verify it is correct&#039;&lt;br /&gt;
Antwort:&lt;br /&gt;
 &#039;`#(1234 555 8888) collect: [:x | x odd ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Evaluating: 1234 is even → 1234 (not 1235). ❌&lt;br /&gt;
 &lt;br /&gt;
 Correct code:&lt;br /&gt;
 `#(1234 555 8888) collect: [:x | x even ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Verify: 1234 even → 1235; 555 odd → 555; 8888 even → 8889... ❌ (should be 8888)&lt;br /&gt;
 &lt;br /&gt;
 The transformation isn&#039;t a simple rule. Looking again: only the first element changes (+1). &lt;br /&gt;
 &lt;br /&gt;
 `#(1234 555 8888) withIndexCollect: [:x :i | i = 1 ifTrue: [x + 1] ifFalse: [x]]`&lt;br /&gt;
 &lt;br /&gt;
 Result: `#(1235 555 8888)` ✓&#039;    &lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
=== Übersetzung ===&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In keinem Fall sollte man der KI &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
=== Arbeit mit Expecco ===&lt;br /&gt;
Um das Modell tatsächlich Code oder Aktionen erzeugen zu lassen reichen die&lt;br /&gt;
einfachsten Modell NICHT;&lt;br /&gt;
Hier eine vorläufige Liste unserer Resultate:&lt;br /&gt;
&lt;br /&gt;
* qwen2.5-coder:3b&amp;lt;br&amp;gt;definitiv zu dumm&lt;br /&gt;
* qwen2.5-coder:7b&amp;lt;br&amp;gt;nach einigen Verbesserungen an den initialen Anweisungen zum Gebrauch der expecco tools kann das Model: Browser öffnen, Projekt anlegen.&amp;lt;br&amp;gt;Achtung: benötigt contextSize=8192; mit 4096 ist es zu vergesslich&lt;br /&gt;
* &lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31550</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31550"/>
		<updated>2026-07-29T07:29:49Z</updated>

		<summary type="html">&lt;p&gt;Sv: 26.2: AI Coding - Claude Code (subscription) provider; Explain Class / Generate Class Documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
* Feature: bridged Scheme (currently only Racket Scheme) action blocks&lt;br /&gt;
* Feature: bridged Octave/Matlab action blocks&lt;br /&gt;
* Feature: bridged C# action blocks&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; AI Coding provider &amp;quot;&#039;&#039;&#039;Claude Code (subscription)&#039;&#039;&#039;&amp;quot; — uses your existing Claude subscription via the locally installed &#039;&#039;Claude Code&#039;&#039; command line program instead of an API key, so no key has to be entered and no per-token API charges are billed. Choose it like any other provider in the settings dialog (Plugins → AI Coding); the API key, endpoint URL and proxy fields are hidden for it because they do not apply, and the authentication method reads &amp;quot;Subscription (external login)&amp;quot;. It requires &#039;&#039;Claude Code&#039;&#039; to be installed and logged in once (run &amp;lt;code&amp;gt;claude&amp;lt;/code&amp;gt; in a terminal and complete the login). The model is selectable either as a tier alias (&#039;&#039;sonnet&#039;&#039;, &#039;&#039;opus&#039;&#039;, &#039;&#039;haiku&#039;&#039; — always the current model of that tier) or as a pinned model id.&lt;br /&gt;
* Feature: two new AI actions that work on the selected &#039;&#039;&#039;class&#039;&#039;&#039; rather than on a single method, reachable from the &#039;&#039;&#039;AI&#039;&#039;&#039; menu of the class browser: &amp;quot;&#039;&#039;&#039;Explain Class&#039;&#039;&#039;&amp;quot; explains the class as a whole — what it is responsible for, what its instance variables hold and how its protocols fit together — and &amp;quot;&#039;&#039;&#039;Generate Class Documentation&#039;&#039;&#039;&amp;quot; proposes a class documentation text which the &amp;quot;[Apply]&amp;quot; button installs into the class&#039; documentation.&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039;, &#039;&#039;&#039;ollama&#039;&#039;&#039; and others as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via [[Tools_FileBrowser/en|FileBrowser]])&lt;br /&gt;
* Feature: public/private keypair generation via a [[Tools_FileBrowser/en|FileBrowser]] menu (for easy SSH setup)&lt;br /&gt;
* Improvement: Bundled python3 installer updated to version 3.13.14&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed the [[Number_API_Functions|Number]] stack (see also in [[Numeric_Limits/en| Numeric Limits]]):&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. and type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan). Now all test cases produce a result within the precision limits of their type&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]&lt;br /&gt;
* UI: &#039;&#039;&#039;Ctrl-Return&#039;&#039;&#039; now accepts the default action in every modal dialog — both the modern SimpleDialog-based ones (check-in log message, search dialogs, ...) and old-style DialogBox-based ones (EnterBox, OptionBox, InfoBox, ...). Unlike plain Return, Ctrl-Return submits the dialog even when the focus is on a multi-line text editor (which normally keeps Return as a newline), so there is no need to tab off the editor first.&lt;br /&gt;
* UI: Transcript (the console) always appends text at end.&lt;br /&gt;
* UI: Transcript does not scroll to end on incoming text while moving the scrollbar &lt;br /&gt;
* Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
* Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
* Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Performance: speedup of cryptographic algorithms (affects key generation and other)&lt;br /&gt;
* Performance: tuned loading of stored ets/elf files (30-40% speedup)&lt;br /&gt;
* Performance: further speedup when loading test-result archives that embed large execution logs — typical load is roughly a third faster again&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31532</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31532"/>
		<updated>2026-07-21T14:42:04Z</updated>

		<summary type="html">&lt;p&gt;Sv: Release 26.1: add Ctrl-Return default-button UI entry&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
* Feature: bridged Scheme (currently only Racket Scheme) action blocks&lt;br /&gt;
* Feature: bridged Octave/Matlab action blocks&lt;br /&gt;
* Feature: bridged C# action blocks&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039;, &#039;&#039;&#039;ollama&#039;&#039;&#039; and others as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via [[Tools_FileBrowser/en|FileBrowser]])&lt;br /&gt;
* Feature: public/private keypair generation via a [[Tools_FileBrowser/en|FileBrowser]] menu (for easy SSH setup)&lt;br /&gt;
* Improvement: Bundled python3 installer updated to version 3.13.14&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed the [[Number_API_Functions|Number]] stack (see also in [[Numeric_Limits/en| Numeric Limits]]):&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. and type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan). Now all test cases produce a result within the precision limits of their type&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]&lt;br /&gt;
* UI: &#039;&#039;&#039;Ctrl-Return&#039;&#039;&#039; now accepts the default action in every modal dialog — both the modern SimpleDialog-based ones (check-in log message, search dialogs, ...) and old-style DialogBox-based ones (EnterBox, OptionBox, InfoBox, ...). Unlike plain Return, Ctrl-Return submits the dialog even when the focus is on a multi-line text editor (which normally keeps Return as a newline), so there is no need to tab off the editor first.&lt;br /&gt;
* UI: Transcript (the console) always appends text at end.&lt;br /&gt;
* UI: Transcript does not scroll to end on incoming text while moving the scrollbar &lt;br /&gt;
* Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
* Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
* Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Performance: speedup of cryptographic algorithms (affects key generation and other)&lt;br /&gt;
* Performance: tuned loading of stored ets/elf files (30-40% speedup)&lt;br /&gt;
* Performance: further speedup when loading test-result archives that embed large execution logs — typical load is roughly a third faster again&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31436</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31436"/>
		<updated>2026-06-19T13:11:46Z</updated>

		<summary type="html">&lt;p&gt;Sv: add AI Coding license-feature note at top&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Die hier beschriebenen KI-Funktionen sind Teil des Lizenz-Features &#039;&#039;&#039;AI Coding&#039;&#039;&#039;.  Ist dieses Feature in Ihrer Lizenz nicht enthalten, erscheinen die &#039;&#039;Ask AI&#039;&#039;-Menüeinträge zwar weiterhin sichtbar in den Editor-Toolbars, sind aber deaktiviert (Tooltip: &amp;quot;Install the AI coding plugin to enable&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
Zusätzlich gibt es noch einen weiteren Eintrag &#039;&#039;&#039;Inhause&#039;&#039;&#039;; dieser ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe OpenAI chatGPT Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren mit beiden Anbietern; bei&lt;br /&gt;
OpenAI nur mit vision-fähigen Modellen (gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic oder OpenAI.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;.  Es gibt keinen eXept-seitigen Proxy oder&lt;br /&gt;
Zwischenspeicher.  Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Sub-Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell&lt;br /&gt;
als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens - wie hier der Fall - werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, daß die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls im typischerweise Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen. Mit &amp;quot;/mcps&amp;quot; sollten die beiden aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen - es sei denn sie dienen der Entscheidung - weg. Tatsächlich erhöhen sie den Tokenverbrauch u.U.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (z.B. ollama) ==&lt;br /&gt;
&lt;br /&gt;
Erste Versuche sind eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In jedem Fall darf man der KI nicht &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31435</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31435"/>
		<updated>2026-06-19T12:44:39Z</updated>

		<summary type="html">&lt;p&gt;Sv: note that config entries are written automatically on MCP server start&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
Zusätzlich gibt es noch einen weiteren Eintrag &#039;&#039;&#039;Inhause&#039;&#039;&#039;; dieser ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe OpenAI chatGPT Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren mit beiden Anbietern; bei&lt;br /&gt;
OpenAI nur mit vision-fähigen Modellen (gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic oder OpenAI.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;.  Es gibt keinen eXept-seitigen Proxy oder&lt;br /&gt;
Zwischenspeicher.  Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Sub-Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell&lt;br /&gt;
als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens - wie hier der Fall - werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, daß die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten ==&lt;br /&gt;
&lt;br /&gt;
Beim Start der MCP-Server-Anbindung trägt expecco die nötigen Konfigurationseinträge automatisch in die Config-Dateien der unterstützten Coding-Assistenten ein.  Die folgenden Abschnitte beschreiben Ort und Format der jeweiligen Einträge — zur Information bzw. falls Sie sie manuell ergänzen oder kontrollieren möchten.&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls im typischerweise Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen. Mit &amp;quot;/mcps&amp;quot; sollten die beiden aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen - es sei denn sie dienen der Entscheidung - weg. Tatsächlich erhöhen sie den Tokenverbrauch u.U.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (z.B. ollama) ==&lt;br /&gt;
&lt;br /&gt;
Erste Versuche sind eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In jedem Fall darf man der KI nicht &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31434</id>
		<title>KI Coding Plugin</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=KI_Coding_Plugin&amp;diff=31434"/>
		<updated>2026-06-19T12:39:15Z</updated>

		<summary type="html">&lt;p&gt;Sv: add Cursor and Zed sections; fill in Tabnine stub (MCP HTTP setup)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= KI Coding Plugin =&lt;br /&gt;
&lt;br /&gt;
Das KI Coding Plugin bindet einen Large Language Model (LLM) basierten&lt;br /&gt;
KI-Assistenten in den Activity-Editor (Aktivitäten-Code), den&lt;br /&gt;
Compound-Netzwerk-Editor, den Dokumentations-Editor und in den&lt;br /&gt;
ST/X Class Browser ein.  Das Plugin unterstützt mehrere Anbieter, die im&lt;br /&gt;
Einstellungsdialog umschaltbar sind:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039; (claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5)&lt;br /&gt;
* &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; (gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1, o3)&lt;br /&gt;
* &#039;&#039;&#039;Ollama&#039;&#039;&#039; lokal oder remote (codellama:7b, codellama:13b)&lt;br /&gt;
Zusätzlich gibt es noch einen weiteren Eintrag &#039;&#039;&#039;Inhause&#039;&#039;&#039;; dieser ist für eigene, firmeninterne KI vorgesehen.&lt;br /&gt;
:: Anm.: tatsächlich sprechen all hinterher das selbe OpenAI chatGPT Protokoll; sie können also auch unter irgend einem anderen Anbieter einfach die URL zu ihrer eignene KI eingeben. Dieser Eintrag dient also lediglich der Übersichtlichkeit, und einem Platz wo Sie Ihre Zugangsdaten ablegen können, wenn Sie doch noch zwischen durch mit anderen Anbietern chatten können und wollen ohne jedesmal die URLs und API keys neu eingeben zu müssen.&lt;br /&gt;
&lt;br /&gt;
Je nach gewähltem Anbieter erscheint die Toolbar-Schaltfläche als&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; ; das Einstellungs-Tab&lt;br /&gt;
heißt &amp;quot;&amp;lt;code&amp;gt;AI Coding&amp;lt;/code&amp;gt;&amp;quot;, unter Plugins (Erweiterungen).&lt;br /&gt;
&lt;br /&gt;
== Aktivitäten-Editor ==&lt;br /&gt;
&lt;br /&gt;
Im Aktivitäten-Code-Editor erscheint in der Toolbar eine Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask Claude&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Ask ChatGPT&amp;lt;/code&amp;gt; mit folgenden Aktionen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Open KI Window&#039;&#039;&#039; — öffnet das eigenständige Chat-Fenster&lt;br /&gt;
* &#039;&#039;&#039;Explain code&#039;&#039;&#039; — erklärt den Code der aktuellen Aktivität&lt;br /&gt;
* &#039;&#039;&#039;Suggest improvement&#039;&#039;&#039; — schlägt Verbesserungen vor&lt;br /&gt;
* &#039;&#039;&#039;Find bugs&#039;&#039;&#039; — sucht nach Fehlern, Race Conditions, nil-Handling-Problemen&lt;br /&gt;
* &#039;&#039;&#039;Generate doc-comment&#039;&#039;&#039; — generiert eine Aktivitäts-Dokumentation inklusive Pin-Kommentaren und füllt den Documentation-Tab&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt...&#039;&#039;&#039; — freier Prompt; der Aktivitäts-Code wird als Kontext mitgesendet&lt;br /&gt;
* &#039;&#039;&#039;Set model&#039;&#039;&#039; ▸ — Untermenü mit den Modellen des aktiven Anbieters (das aktuell aktive Modell ist mit &#039;&#039;(active)&#039;&#039; markiert)&lt;br /&gt;
* &#039;&#039;&#039;Set provider&#039;&#039;&#039; ▸ — nur sichtbar, wenn API-Schlüssel für mehr als einen Anbieter konfiguriert sind; Untermenü zum Umschalten zwischen Claude, ChatGPT oder anderem Anbieter&lt;br /&gt;
&lt;br /&gt;
Code-Vorschläge können mit &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; (direkt am jeweiligen&lt;br /&gt;
Code-Block im Chat oder über die obere Apply-Schaltfläche) in den&lt;br /&gt;
Aktivitäts-Body übernommen werden.  Vom KI gelieferte Smalltalk/X&lt;br /&gt;
Hilfsmethoden (Form: &amp;lt;code&amp;gt;Klasse &amp;gt;&amp;gt; selector&amp;lt;/code&amp;gt;) werden nach&lt;br /&gt;
Rückfrage in die genannte Klasse compiliert.&lt;br /&gt;
&lt;br /&gt;
== Compound (Netzwerk) Editor ==&lt;br /&gt;
&lt;br /&gt;
Auf der Toolbar von Compound-Worksheets erscheint dieselbe&lt;br /&gt;
Schaltfläche, beschränkt auf die für Netze sinnvollen Aktionen&lt;br /&gt;
(&#039;&#039;Open KI Window&#039;&#039;, &#039;&#039;Generate doc-comment&#039;&#039;) — ebenfalls mit den&lt;br /&gt;
Untermenüs &#039;&#039;Set model&#039;&#039; und ggf. &#039;&#039;Set provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Dokumentations-Editor ==&lt;br /&gt;
&lt;br /&gt;
Der Dokumentations-Tab der Block-Description (Editor für Test-Cases,&lt;br /&gt;
Test-Plans und Aktivitäten) trägt dieselbe Toolbar-Schaltfläche&lt;br /&gt;
&amp;lt;code&amp;gt;Ask ...&amp;lt;/code&amp;gt; mit den obigen Einträgen&lt;br /&gt;
&#039;&#039;Generate doc-comment&#039;&#039; analysiert den aktuellen Block (Name,&lt;br /&gt;
vorhandene Beschreibung, Eingangs-/Ausgangs-Pins, Sub-Steps eines&lt;br /&gt;
Compound-Netzes, referenzierte Environment-Variablen) und schlägt&lt;br /&gt;
eine vollständige Block- und Pin-Dokumentation vor.&lt;br /&gt;
&lt;br /&gt;
Ist der Block schreibgeschützt (importierte Library, RTL-Lizenz),&lt;br /&gt;
fragt &amp;lt;code&amp;gt;[Apply]&amp;lt;/code&amp;gt; nach, ob der Block freigeschaltet und die&lt;br /&gt;
Dokumentation eingetragen werden soll.&lt;br /&gt;
&lt;br /&gt;
== Class Browser (ST/X) ==&lt;br /&gt;
&lt;br /&gt;
Im Class Browser stehen die Aktionen unter dem &#039;&#039;&#039;AI&#039;&#039;&#039;-Untermenü&lt;br /&gt;
sowie im Selektor-Kontextmenü zur Verfügung.  Die Aktionen&lt;br /&gt;
operieren auf der aktuell ausgewählten Methode (Klasse + Selektor +&lt;br /&gt;
Quelltext werden als Kontext mitgesendet).  &#039;&#039;&#039;[Apply]&#039;&#039;&#039; kann das&lt;br /&gt;
Resultat direkt in die Methode der aktiven Klasse einbauen.&lt;br /&gt;
Auch hier sind &#039;&#039;&#039;Set model&#039;&#039;&#039; und ggf. &#039;&#039;&#039;Set provider&#039;&#039;&#039; als&lt;br /&gt;
Untermenüs verfügbar.&lt;br /&gt;
&lt;br /&gt;
== Chat-Fenster ==&lt;br /&gt;
&lt;br /&gt;
Das eigenständige Chat-Fenster trägt den Titel&lt;br /&gt;
&#039;&#039;&#039;AI Coding [&amp;amp;lt;Produkt&amp;amp;gt; / &amp;amp;lt;Modell&amp;amp;gt;]&#039;&#039;&#039; (z.B.&lt;br /&gt;
&amp;quot;AI Coding [Claude / claude-opus-4-7]&amp;quot;) und zeigt nach jedem Turn&lt;br /&gt;
den Tokenverbrauch und die kumulierten Kosten — sofern Preise für&lt;br /&gt;
das gewählte Modell hinterlegt sind.  Anbieter- und Modellwechsel&lt;br /&gt;
im Einstellungsdialog werden live übernommen.&lt;br /&gt;
&lt;br /&gt;
Das Transkript ist als vertikales Panel von &amp;quot;Karten&amp;quot; aufgebaut:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Prosa-Karten&#039;&#039;&#039; enthalten den fließenden Text der Antwort; Zeilen werden auf die Fenster-Breite umgebrochen.&lt;br /&gt;
* &#039;&#039;&#039;Code-Karten&#039;&#039;&#039; (eingerahmt) entstehen aus markdown-Code-Blöcken (&amp;lt;code&amp;gt;```...```&amp;lt;/code&amp;gt;) und sind als &#039;&#039;&#039;Workspace&#039;&#039;&#039; editierbar — das Standard-Smalltalk-Popup-Menü bietet doIt / printIt / inspectIt, ein &amp;lt;code&amp;gt;TestCase&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;simulatedSelf&amp;lt;/code&amp;gt; ist gesetzt, so dass &amp;lt;code&amp;gt;self assert:... equals:...&amp;lt;/code&amp;gt; direkt ausgeführt werden kann.  Lange Blöcke scrollen innerhalb der Karte.  Rechts oben sitzen die Schaltflächen &#039;&#039;&#039;[Apply]&#039;&#039;&#039; (sofern für den Kontext sinnvoll) und &#039;&#039;&#039;[⎘ Copy]&#039;&#039;&#039;; links wird der Sprachtag (smalltalk, python, …) angezeigt.&lt;br /&gt;
* &#039;&#039;&#039;Doku-Karten&#039;&#039;&#039; (volle Breite, Prosa) entstehen aus dem speziellen &amp;lt;code&amp;gt;```doc&amp;lt;/code&amp;gt;-Block, den der Dokumentations-Generator anfordert; Inhalt ist die Vorschlags-Dokumentation für Block- und Pin-Beschreibungen.&lt;br /&gt;
&lt;br /&gt;
Scroll-Lock: solange der Anwender bereits am unteren Ende des&lt;br /&gt;
Transkripts steht, folgt die Anzeige neu eintreffenden Karten&lt;br /&gt;
automatisch; nach manuellem Hochscrollen bleibt die Position stehen.&lt;br /&gt;
&lt;br /&gt;
Bilder können als Anhang versendet werden (Screenshot oder&lt;br /&gt;
PNG/JPG-Datei).  Anhänge funktionieren mit beiden Anbietern; bei&lt;br /&gt;
OpenAI nur mit vision-fähigen Modellen (gpt-4o-Familie).&lt;br /&gt;
&lt;br /&gt;
== Einstellungen (AI Coding) ==&lt;br /&gt;
&lt;br /&gt;
Im Einstellungsdialog unter &#039;&#039;&#039;Plugins → AI Coding&#039;&#039;&#039; (bzw. unter&lt;br /&gt;
&#039;&#039;&#039;Tools → AI Coding&#039;&#039;&#039; im Smalltalk-Launcher) werden konfiguriert:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Provider&#039;&#039;&#039; — Anthropic oder OpenAI.  Beim Wechsel werden API-URL und Default-Modell entsprechend angepasst; der gespeicherte API-Schlüssel des jeweiligen Anbieters wird geladen.&lt;br /&gt;
* &#039;&#039;&#039;API Key&#039;&#039;&#039; — Schlüssel des aktuell gewählten Anbieters.  Die Schlüssel werden pro Anbieter getrennt gespeichert (&amp;lt;code&amp;gt;#claudeApiKey_anthropic&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;#claudeApiKey_openai&amp;lt;/code&amp;gt;), so dass zwischen den Anbietern ohne erneute Eingabe gewechselt werden kann.  Das Setzen des Schlüssels erfolgt ausschließlich über diesen Dialog.&lt;br /&gt;
* &#039;&#039;&#039;Model&#039;&#039;&#039; — ein Modell aus der Liste des aktiven Anbieters oder ein selbst eingegebener Modellname.  Kann auch direkt über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü in den Editor-Toolbars umgeschaltet werden.&lt;br /&gt;
* &#039;&#039;&#039;Max output tokens&#039;&#039;&#039; — maximale Antwortlänge.&lt;br /&gt;
* &#039;&#039;&#039;API URL&#039;&#039;&#039; — nur zu ändern für eigene Proxies / Gateways.  Standard: &amp;lt;code&amp;gt;https://api.anthropic.com/v1/messages&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;https://api.openai.com/v1/chat/completions&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== API-Schlüssel beschaffen ==&lt;br /&gt;
&lt;br /&gt;
* Anthropic: [https://console.anthropic.com console.anthropic.com], Schlüsselformat &amp;lt;code&amp;gt;sk-ant-...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* OpenAI: [https://platform.openai.com/api-keys platform.openai.com/api-keys], Schlüsselformat &amp;lt;code&amp;gt;sk-...&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;sk-proj-...&amp;lt;/code&amp;gt;.  Voraussetzung ist ein aufgeladenes Konto (Mindestbetrag derzeit USD 5).&lt;br /&gt;
&lt;br /&gt;
== Datenschutz / Datenfluss ==&lt;br /&gt;
&lt;br /&gt;
Bei aktivem Anbieter &#039;&#039;&#039;Anthropic&#039;&#039;&#039; gehen die Anfragen direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.anthropic.com&amp;lt;/code&amp;gt;, bei &#039;&#039;&#039;OpenAI&#039;&#039;&#039; direkt an&lt;br /&gt;
&amp;lt;code&amp;gt;api.openai.com&amp;lt;/code&amp;gt;.  Es gibt keinen eXept-seitigen Proxy oder&lt;br /&gt;
Zwischenspeicher.  Mit dem Aktivitäts-Quelltext bzw. den Methoden-&lt;br /&gt;
Quelltexten werden auch Pin-Beschreibungen, Sub-Step-Namen und&lt;br /&gt;
referenzierte Environment-Variablen aus dem Block-Description-Modell&lt;br /&gt;
als Kontext versendet.&lt;br /&gt;
&lt;br /&gt;
Bei Benutzung von Anthropic API-Tokens - wie hier der Fall - werden laut Anthropic die Daten nicht zum Training des KI-Modells genutzt ([https://privacy.claude.com/de/articles/7996868-werden-meine-daten-fur-das-modelltraining-verwendet Anthropic Erkärung dazu]).&amp;lt;br&amp;gt;Für die Wahrheit dieser Aussage können wir nicht garantieren und haften.&amp;lt;br&amp;gt;Zu bedenken ist auch, daß die KI-Modelle nicht in inländischen Rechenzentren laufen, und eventuell weitere &amp;quot;Mitleser&amp;quot; involviert sind. Dies gilt insbesondere für Hightech, KI, Software und Defence Unternehmen, wo Fälle von Wirtschaftsspionage bekannt sind.&lt;br /&gt;
&lt;br /&gt;
⚠ Wenn Sie sicher sein wollen, daß keine Information Ihr Haus verlässt empfehlen wir eine eigenem geschlossene in-House KI Umgebung, wie sie bei einigen unserer Kunden bereits existiert. Sie dürfen dann selbstverständlich nur die URLs dieser Umgebung konfigurieren. Expecco kommuniziert ausschließlich mit der von Ihnen eingegebenen KI.&lt;br /&gt;
&lt;br /&gt;
== Coding Assistenten ==&lt;br /&gt;
&lt;br /&gt;
=== Claude Code ===&lt;br /&gt;
Einträge für den mcp-server werden von expecco in die &amp;lt;code&amp;gt;&amp;quot;.claude.json&amp;lt;/code&amp;gt; Datei (typischerweise in Ihrem Homeverzeichnis) vom Einstellungsdialog eingebracht:&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;http&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  },&lt;br /&gt;
  ...&lt;br /&gt;
danach sollte nach dem Start von &amp;quot;claude.exe&amp;quot; diese mit dem &amp;lt;code&amp;gt;/mcp&amp;lt;/code&amp;gt; Kommando gelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Opencode (mit Zen) ===&lt;br /&gt;
&lt;br /&gt;
Nach der Anmeldung (opencode authlogin) starten Sie opencode erneut. Aktuell müssen die mcp in einem Editor von Ihnen konfiguriert werden (autom. Eintrage in einer späteren Version. Ändern Sie dazu die Datei &amp;quot;&amp;lt;code&amp;gt;.config\opencode\opencode.jsonc&amp;lt;/code&amp;gt;&amp;quot; (ebenfalls im typischerweise Heimatverzeichnis) zu:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,&lt;br /&gt;
  &amp;quot;mcp&amp;quot;: {&lt;br /&gt;
    &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;remote&amp;quot;,&lt;br /&gt;
      &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Sollten Sie ein Komma vergessen haben wird beim Start eine Fehlermeldung erscheinen. Mit &amp;quot;/mcps&amp;quot; sollten die beiden aufgelistet werden.&lt;br /&gt;
&lt;br /&gt;
=== Cursor ===&lt;br /&gt;
Cursor liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.cursor/mcp.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.cursor\mcp.json&amp;lt;/code&amp;gt;).  Ergänzen Sie dort:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Beim nächsten Start von Cursor sollten die Server unter &amp;lt;code&amp;gt;Settings → MCP&amp;lt;/code&amp;gt; als &#039;&#039;connected&#039;&#039; erscheinen.&lt;br /&gt;
&lt;br /&gt;
=== Zed ===&lt;br /&gt;
Zed liest seine MCP-Konfiguration aus &amp;lt;code&amp;gt;~/.config/zed/settings.json&amp;lt;/code&amp;gt; (Windows: &amp;lt;code&amp;gt;%APPDATA%\Zed\settings.json&amp;lt;/code&amp;gt;).  Der Eintrag steht unter dem Schlüssel &amp;lt;code&amp;gt;context_servers&amp;lt;/code&amp;gt; (nicht &amp;lt;code&amp;gt;mcpServers&amp;lt;/code&amp;gt; wie bei den anderen):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;context_servers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Tabnine ===&lt;br /&gt;
Tabnine sucht seine MCP-Konfiguration zuerst projektbezogen unter &amp;lt;code&amp;gt;&amp;amp;lt;Projekt&amp;amp;gt;/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, dann im Homeverzeichnis (&amp;lt;code&amp;gt;~/.tabnine/mcp_servers.json&amp;lt;/code&amp;gt;, Windows: &amp;lt;code&amp;gt;%USERPROFILE%\.tabnine\mcp_servers.json&amp;lt;/code&amp;gt;):&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
     &amp;quot;smalltalk&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;expecco&amp;quot;: {&lt;br /&gt;
       &amp;quot;url&amp;quot;: &amp;quot;http://127.0.0.1:9876/mcp/expecco&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
Alternativ können Sie den Server auch direkt im Tabnine-IDE-Plugin über &amp;lt;code&amp;gt;☰ → ⛭ Settings → Tools and MCPs → MCP servers → + Add MCP server&amp;lt;/code&amp;gt; eintragen.&lt;br /&gt;
&lt;br /&gt;
== Tipps ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mehrere Konversationen&#039;&#039;&#039;: der Chat ist ein Singleton — eine neue Anfrage über ein Browser-/Editor-Menü startet jedesmal eine &#039;&#039;&#039;neue&#039;&#039;&#039; Konversation. Folge-Fragen (Klärung, Vertiefung) gehen über das Eingabefeld in derselben Konversation.&lt;br /&gt;
* &#039;&#039;&#039;Vorsicht:&#039;&#039;&#039; Die Größe der übertragenen Daten (auch die aus dem Chatfenster) geht in die Kostenberechnung ein. Deshalb immer eine neue Konversation starten, wenn es um ein neues Thema geht.&lt;br /&gt;
* &#039;&#039;&#039;Modell wechseln&#039;&#039;&#039;: Für schnelle Routine-Antworten Haiku oder Sonnet, für schwierige Refactorings Opus. Über das &#039;&#039;&#039;Set model&#039;&#039;&#039;-Untermenü direkt aus der Toolbar oder über die Settings.&lt;br /&gt;
* &#039;&#039;&#039;Anbieter wechseln&#039;&#039;&#039;: Sind Schlüssel für beide Anbieter konfiguriert, schaltet das &#039;&#039;&#039;Set provider&#039;&#039;&#039;-Untermenü ohne Umweg über den Settings-Dialog um.&lt;br /&gt;
* &#039;&#039;&#039;Code direkt ausführen&#039;&#039;&#039;: In Code-Karten kann markierter Smalltalk-Code per doIt / printIt / inspectIt direkt evaluiert werden — praktisch z.B. um vom Modell vorgeschlagene SUnit-Asserts gleich auszuprobieren, ohne den Code erst in einen Workspace zu kopieren.&lt;br /&gt;
* &#039;&#039;&#039;Custom prompt&#039;&#039;&#039; eignet sich gut für „warum macht Methode X es so und nicht so?&amp;quot; oder „schreib mir einen ParameterizedTest dazu mit folgenden Daten: …&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Tipps für die Arbeit mit claudeCode ==&lt;br /&gt;
Wenn Sie ClaudeCode oder Opencode verwenden, stehen ihnen noch weit mehr Funktionen zur Verfügung: sie können zum Beispiel im claudeCode Terminal eingeben: &lt;br /&gt;
* &amp;quot;mach mir eine neue Suite in einem neuen Fenster&amp;quot;,&lt;br /&gt;
* &amp;quot;Mache eine Aktion zur Berechnung des Umfangs eines Kreises bei gegebenen Radius&amp;quot;, &lt;br /&gt;
* &amp;quot;Erstelle eine neue Suite mit einem Testfall der folgendes macht: &lt;br /&gt;
** 1) webbrowser auf &amp;quot;www.exept.de&amp;quot; öffnen. &lt;br /&gt;
** 2) auf das logo oben links klicken. &lt;br /&gt;
** 3) webbrowser schliessen.&lt;br /&gt;
* welche Funktionalität ist in xxx.ets&lt;br /&gt;
&lt;br /&gt;
(Anm.: es spielt keine Rolle, ob Sie sich in Deutsch oder Englisch unterhalten)&lt;br /&gt;
 &lt;br /&gt;
Claude wurde von uns in die Lage versetzt, selbst nach passenden Bibliotheken zu suchen, diese zu importieren, Aktionen zu generieren und den Testplan anzulegen.&lt;br /&gt;
&lt;br /&gt;
Tatsächlich auch, den Test gleich durchzuführen und das Resultat zu analysieren.&lt;br /&gt;
&lt;br /&gt;
Aktuell sind wir am trainieren, so dass claude z.B. selbst entscheidet ob es besser ist, eine fehlende Aktion als  Diagramm oder elementa zu definieren. Es ist in der Lage, die Funktionen des unterliegenden Frameworks zu sehen und auch komplexe Aufgaben zu erledigen:&lt;br /&gt;
* &amp;quot;Aktion zum Lesen der Jahresumsätze eines Jahres aus der Datenbank&amp;quot;&lt;br /&gt;
* extrahiere aus dem xml Dokument alle budget Einträge und liefere die Summe&lt;br /&gt;
&lt;br /&gt;
=== Erfahrungen und Tipps für die Arbeit ===&lt;br /&gt;
&lt;br /&gt;
==== Modellwahl; Sonnet, Heiku und Fable ====&lt;br /&gt;
Sonnet-4 ist gefühlt weit intelligenter als Heiku-4.5,&lt;br /&gt;
aber auch weit teurer. Fable ist für sehr komplexe Aufgaben, aber sehr teuer (ich meine: wirklich teuer). Ihr Budget kann sehr schnell schmelzen mit Sonnet - insbesondere wenn man auf medium oder high Intelligenzlevel arbeitet. Haiku macht weit mehr Fehler und man sollte genau hinschauen was er so generiert. Gefühlt war Sonnet selbst im low level besser als Haiku. Aber der Preis...&lt;br /&gt;
Noch besser ist Fable, aber extrem teuer; in einer halben Stunde kann da schon mal das Tagesbudget an Tokens verbraucht werden.&lt;br /&gt;
&lt;br /&gt;
Folgende konkrete Tipps aus unseren ersten Erfahrungen, diese Liste wird aktualisiert, und kann auch basieren auf unserer eigenen Dummheit. Ist also u.U. mit Vorsicht zu genießen.&lt;br /&gt;
&lt;br /&gt;
* geben Sie Haiku mehr Hinweise, z.B. &amp;quot;schau mal dort, oder nimm das als Beispiel&amp;quot;. Sonnet findet selbst viel besser Lösungen.&lt;br /&gt;
&lt;br /&gt;
* kurze Anweisungen, je konkreter desto günstiger.&lt;br /&gt;
&lt;br /&gt;
* Haiku ist weit &amp;quot;fauler&amp;quot;. Z.B hat sonnet automatisch eine Dokumentation bei neuen Aktionen angelegt, und diese auch aktualisiert. Haiku hingegen musste man explizit eine Regel dazu anlegen (z.B. mit &amp;quot;wenn du eine Aktion anlegst oder änderst, aktualisiere die Dokumentation&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
* Heiku ist dümmer. Regeln die von Sonnet angelegt wurden, können von Haiku u.U. nicht befolgt werden, weil Sonnet weit mehr generalisieren kann.&lt;br /&gt;
&lt;br /&gt;
* sagen Sie allen sie sollten wenn sie ein Problem haben,  nicht lange selbst suchen. sondern nachfragen ob man ihnen einen Tipp geben kann. Wenn Sie das nicht tun, kann es sein dass Sonnet auch eine viertel Stunde nachdenkt und die Dollars schmelzen wie Eis in der Sonne&amp;lt;br&amp;gt;(ist mir passiert, als ein Socket Problem in der Kommunikation auftrat, und er nicht erkannte, das die Antworten von mcp falsch waren, es hat dann selbst alle möglichen Wege gesucht, eine Nachricht abzusetzen, incl. der Erstellung diverser Shell, curl und Python Scripte... obgleich es eigentlich ein Interface dafür gab, das aber einen Fehler hatte). Insbesondere hatte ich dummerweise vorher sinngemäß gesagt er solle, wenn ein Problem auftritt dies und jenes tun, wobei dabei genau dieses Problem wieder auftrat...&lt;br /&gt;
&lt;br /&gt;
* schränken Sie das Modell in seinen Möglichkeiten ein, z.B. sagen sie &amp;quot;editiere nicht die files sondern verwende dazu ein tool&amp;quot;, oder &amp;quot;eine expecco Aktion und sag mir vorher welche du nimmst&amp;quot;. Sonst kann es passieren dass es anfängt ihre ets zu entpacken um darin nach Strings zu suchen, obgleich es das eigentlich einfacher über das interface machen kann (dieses konkrete Problem wird nicht mehr auftreten aber Sie sehen den Punkt). Da war Sonnet weit intelligenter hat aber auch länger nachgedacht. &lt;br /&gt;
&lt;br /&gt;
* wenn sie feststellen, dass es einen Fehler macht, sagen sie (mehr oder weniger wörtlich) &amp;quot;remember: mach dies nicht, oder um das zu machen tu das.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* sie können diese Erinnerungen sowohl in ihrem UserProfile (also im lokalen Filesystem) als auch in ihren expecco Präferenzen halten. Sagen Sie dazu &amp;quot;remember this in in my expecco preferences&amp;quot; oder &amp;quot;remember (in my user memory): bla bla&amp;quot;. Erinnerungen kann man auch löschen &amp;quot;forget to ...&amp;quot;. Zu Beginn der nächsten Session sagen sie &amp;quot;read the expecco preferences memory&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* wechseln sie das Modell oder den level, je nach Komplexität der Aufgabe. Aber bedenken Sie dass Wissen von Session zu Session verloren geht, wenn es nicht erinnert wird. Technisch sind Erinnerungen nichts anderes als das Lesen einer Liste der vormaligen remember Anweisungen. Kosten also auch Tokens. Sie könnten also die Erinnerungen auch einfach neu eintippen ;-)&lt;br /&gt;
&lt;br /&gt;
* Fable ist ein echter Star, wenn es darum geht, z.B. eine komplexe Architektur zu entwerfen. Mein Tipp: lassen sie ihn einen Plan machen, und von einem einfacheren Modell Schritt für Schritt umsetzen.&lt;br /&gt;
&lt;br /&gt;
* auch wenn es so scheint: das &amp;quot;Ding&amp;quot; ist kein Mensch; lassen sie &amp;quot;bitte, danke, oder Begründungen - es sei denn sie dienen der Entscheidung - weg. Tatsächlich erhöhen sie den Tokenverbrauch u.U.&lt;br /&gt;
&lt;br /&gt;
Subjektive Zusammenfassung: &lt;br /&gt;
* Haiku ist viel schneller in der Antwort und kostet ein Zehntel. Mit Sonnet war nach 3-4 Std Arbeit mein Limit erreicht und ich durfte Stunden Pause machen. Mit Fable kann schon nach 1/2 Stunde die Zwangspause erzwungen werden. Mit Haiku kann man durcharbeiten. Aber ich brauche auch mindestens doppelt so viel Zeit um Haiku anzuleiten und seine Fehler wieder auszubügeln.&lt;br /&gt;
&lt;br /&gt;
== Was kann eine lokale KI (z.B. ollama) ==&lt;br /&gt;
&lt;br /&gt;
Erste Versuche sind eher ernüchternd. Ohne Zugriff auf lokale Quellen &amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt;, mit rein antrainiertem Wissen sind die Modelle vermutlich zu klein. Hier eine Konversation mit gemma3:8b-it-qat (8 Mrd, quantifiziert) auf einem Rechner ohne GPU.&lt;br /&gt;
Die Antwortzeiten sind natürlich schlecht, aber mit einer GPU u.U. brauchbar. Wenn Sie im Haus Zugriff auf Rechner mit GPU haben sollten Sie diese unbedingt nutzen (mit möglichst viel RAM, damit die Modelle auch hineinpassen!)&lt;br /&gt;
&lt;br /&gt;
Wichtig: wir sind selbst noch Anfänger und keine [https://en.wikipedia.org/wiki/Susan_Calvin KI Psychologen].&lt;br /&gt;
Aber die Erfahrungen werden aktuell in einem Feintuning Prozess in die nächste Release eingebracht.&lt;br /&gt;
  &lt;br /&gt;
&amp;lt;sup&amp;gt;1)&amp;lt;/sup&amp;gt; z.B. über mcp tools, welche wir in der aktuellen Version für claudeCode bereits implementiert haben.&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
 install ollama&lt;br /&gt;
 ollama pull gemma3:8b-it-qat ;; gemma3:8b / gemma3:12b usw.&lt;br /&gt;
 ollama run gemma3:8b-it-qat&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 1 ===&lt;br /&gt;
Hinweise: Wichtig, sonst labert Sie das Modell voll!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; respond short and concise&lt;br /&gt;
 Understood&lt;br /&gt;
&lt;br /&gt;
Hinweise: Smalltalk/X wissen hat er nicht, aber VW und Pharo sind ähnlich genug.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are an expert in smalltalk programming, especially in Smalltalk/X, visualworks and Squeak.&lt;br /&gt;
 &lt;br /&gt;
 You have come to the right place I have a considerable depth of knowledge regarding Smalltalk...&lt;br /&gt;
Angeber- wir werden sehen&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what does the smalltalk expression &amp;quot;self at:4 put:&#039;bla&#039; &amp;quot; mean&lt;br /&gt;
 &lt;br /&gt;
 Sets the character &#039;b&#039; at index 4 of `self` (assuming `self` is a string).&lt;br /&gt;
Falsche Antwort; Smalltalk verwendet 1-basierte Indices, und &#039;bla&#039; ist ein String&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to compute the area of a circle given radius&lt;br /&gt;
 &lt;br /&gt;
 ```smalltalk&lt;br /&gt;
 | radius area |&lt;br /&gt;
 radius := 5.0.&lt;br /&gt;
 area := radius * radius * PI.&lt;br /&gt;
 ^area&lt;br /&gt;
 ```&lt;br /&gt;
nicht schlecht. PI gibt es zwar nicht als globale Variable (richtig wäre &amp;quot;Float pi&amp;quot;), aber dennoch bemerkenswert.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; how to extract a substring&lt;br /&gt;
 &lt;br /&gt;
 `substring:startIndexToEndIndex` (inclusive). E.g., `&amp;quot;hello&amp;quot; substring:2 to:4` yields `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
wieder falsch; 1-basierter index, substring:to: möglicherweise in einem anderen Smalltalk vorhanden. Könnte man durchgehen lassen.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; alternative?&lt;br /&gt;
 &lt;br /&gt;
 `copyFrom:to:` (indexes inclusive). `string copyFrom:1 to:3` gives `&amp;quot;ell&amp;quot;`.&lt;br /&gt;
besser, aber immer noch falscher Index&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;hello&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &amp;quot;llo&amp;quot;&lt;br /&gt;
war zu erwarten&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; smalltalk uses 1 based indexing. what is the result&lt;br /&gt;
 &lt;br /&gt;
 Correct. The result of `&#039;hello&#039; copyFrom:2 to:4` is `&amp;quot;llo&amp;quot;`.&lt;br /&gt;
soso. Er sieht ein, dass ich korrigiert habe - dann aber dickköpfig.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; in smalltalk the first index is 1 the last is the collection&#039;s size. Not as in Python or C.&lt;br /&gt;
 &lt;br /&gt;
 Precisely. 1-based indexing is core to Smalltalk.&lt;br /&gt;
aha, er könnte es wissen; es fehlt ihm aber offensichtlich an Abstraktionsvermögen. Versuchen wir es mit einem Beispiel:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 You are absolutely right! My apologies. `copyFrom:to:` includes both endpoints, so `&#039;hello&#039; copyFrom:2 to:4` results in `&amp;quot;ell&amp;quot;`. Thanks for the correction. I am still under development and learning nuances like this.&lt;br /&gt;
soso, eine Nuance. Und eigentlich hatte ich gesagt, er solle kurz und exakt antworten. Die Entschuldigungen kann er sich sparen. Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;bcd&amp;quot;&lt;br /&gt;
na also; geht doch.&lt;br /&gt;
&lt;br /&gt;
=== Sitzung 2 ===&lt;br /&gt;
&lt;br /&gt;
Neuer Versuch; eine neue Session. Gib ihm Grundwissen, das er nicht im Modell hat.&lt;br /&gt;
 /clear&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; answer short an concise&lt;br /&gt;
 Okay.&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; you are expert in smalltalk programming, especially smalltalk/x, visualworks and pharo&lt;br /&gt;
 &lt;br /&gt;
 Acknowledged. I&#039;m ready to leverage my knowledge of Smalltalk (including Smalltalk/X, VisualWorks, and Pharo) to assist you. Ask away!&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; remember: because smalltalk is 1-based indexing, the result of &#039;hello&#039; copyFrom:2 to4 is &#039;ell&#039;&lt;br /&gt;
 &lt;br /&gt;
 Understood. I will keep in mind Smalltalk&#039;s 1-based indexing when answering your questions about string manipulation and other operations&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; what is the result of &#039;abcde&#039; copyFrom:2 to:4&lt;br /&gt;
 &lt;br /&gt;
 &#039;bcd&#039;&lt;br /&gt;
richtig!&amp;lt;br&amp;gt;&lt;br /&gt;
Hätte ich hinzufügen müssen, daß das nicht nur für Strings gilt? Mal sehen:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt;&amp;gt;&amp;gt; given Array #(10 20 30 40) what is the result of array at:3&lt;br /&gt;
 &lt;br /&gt;
 30&lt;br /&gt;
richtig!&lt;br /&gt;
&lt;br /&gt;
Man muss den Kontext also mit Wissen füllen (oder fein tuning, wozu aber unsere GPU vermutlich nicht in der Lage ist), dann kommt durchaus sinnvolles heraus. Wir sind dran, das zu evaluieren damit möglicherweise sogar eine lokale KI (allerdings mit GPU) hilfreich unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
=== Versuche mit qwen2.5-coder:7b ===&lt;br /&gt;
Dieser zeigt erstaunlich gute Antworten auf unserer lokalen ollama installtaion mit einer (nach heutigem Maßstab) durchschnittlichen GPU (Preis heute ca. 1500.-)&lt;br /&gt;
&lt;br /&gt;
== Wahl der Modellgrösse ==&lt;br /&gt;
&lt;br /&gt;
Versuche mit gemma3:270m (sehr klein; 270Mio), gemma3:1b (1 Mrd) und gemma3:4b (4 Mrd).&amp;lt;br&amp;gt;Alle auf lokalem Rechner ohne GPU (was keinen Einfluss auf die Antwort hat, aber die Antwortzeit bestimmt).&lt;br /&gt;
&lt;br /&gt;
Versuch: Übersetzung einer Bausteindokumentation.&lt;br /&gt;
&lt;br /&gt;
Eingabe: translate to German:&lt;br /&gt;
 &amp;quot;show a dialog with an informationstring&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Die 270m und 1b Modelle kennen das Geschlecht nicht; sie drücken sich etwas ungeschickt aus:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;Zeigen Sie eine Dialoge mit einer Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen: &lt;br /&gt;
   &amp;quot;Zeige einen Dialog mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
   &amp;quot;Zeige eine Dialoge mit einer Informationsstring.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
bzw (1Mrd).&lt;br /&gt;
 &amp;quot;Zeig eine Dialog mit einem Informationsstring&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Gib ein Dialog mit einem Informationen-String aus&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige einen Dialog, der eine Informations-Stränge enthält&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das 4Mrd Modell scheint brauchbar:&lt;br /&gt;
 &amp;quot;Zeige einen Dialog mit einer Informationsnachricht&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 Alternativen:&lt;br /&gt;
 &amp;quot;Erstelle ein Dialogfenster mit einer Informationsanzeige&amp;quot;&lt;br /&gt;
 &amp;quot;Zeige ein Dialogfeld mit einer Informationen&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In jedem Fall darf man der KI nicht &amp;quot;blind&amp;quot; vertrauen.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Plugin]]&lt;br /&gt;
[[Kategorie:Erweiterung]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31405</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31405"/>
		<updated>2026-06-08T14:26:29Z</updated>

		<summary type="html">&lt;p&gt;Sv: password authentication: URL form, code API, auth order; launcher menu entries&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on OpenSSL or libssh.  Use this for anything that touches credentials or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine. Used for local-tool integration and for the local end of a remote workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No encryption, passwords on the wire in clear.  Use only when the target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
&amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt; subclass that lets the rest of ST/X treat a remote SFTP path the same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user[:password]@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.  The optional &amp;lt;code&amp;gt;:password&amp;lt;/code&amp;gt; piece is the&lt;br /&gt;
RFC-3986-style userinfo password &amp;amp;mdash; see&lt;br /&gt;
[[#Password authentication]] for when this is appropriate and what&lt;br /&gt;
the security trade-offs are.  When present, it is used as a USERAUTH&lt;br /&gt;
fallback after the normal publickey/agent attempts and is &#039;&#039;&#039;never&#039;&#039;&#039;&lt;br /&gt;
re-emitted by the printable URL form, so logging the filename does&lt;br /&gt;
not leak the credential.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Refresh&#039;&#039;&#039; button in the toolbar (the round-arrow icon&lt;br /&gt;
between &#039;&#039;Forward&#039;&#039; and &#039;&#039;DirectoryUp&#039;&#039;) re-reads both the&lt;br /&gt;
directory tree and the contents pane on demand.  Works uniformly&lt;br /&gt;
for local and SFTP paths; for SFTP it also flushes the per-file&lt;br /&gt;
STAT cache, so changes made directly on the remote side become&lt;br /&gt;
visible immediately rather than waiting for the 5-second cache TTL&lt;br /&gt;
to expire.&lt;br /&gt;
&lt;br /&gt;
The small arrow next to the Refresh icon opens a dropdown with a&lt;br /&gt;
single checkbox, &#039;&#039;&#039;Automatic Refresh&#039;&#039;&#039;, controlling the&lt;br /&gt;
background polling task that walks every expanded tree item to&lt;br /&gt;
detect external changes.  The default depends on the current root:&lt;br /&gt;
&lt;br /&gt;
* Local filesystem &amp;amp;rarr; &#039;&#039;&#039;on&#039;&#039;&#039; (10-second cycle, matches the long-standing behaviour).&lt;br /&gt;
* SFTP &amp;amp;rarr; &#039;&#039;&#039;off&#039;&#039;&#039;.  Each cycle costs one STAT round-trip per child, which is fine for a handful of local directories but painful over the network.  Click Refresh manually when you need to pick up remote changes.&lt;br /&gt;
&lt;br /&gt;
When you navigate between local and SFTP roots the toggle flips&lt;br /&gt;
automatically &amp;amp;mdash; but only if you haven&#039;t overridden it for&lt;br /&gt;
the previous root.  An explicit user choice is preserved across&lt;br /&gt;
navigations.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of the filesystem holding the currently displayed directory.  Works uniformly for local paths and SFTP paths; for SFTP it requires the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; extension (every modern OpenSSH does).  Sizes are reported in IEC binary units (MiB, GiB, TiB) — the largest unit yielding a value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039; rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From the Launcher ==&lt;br /&gt;
&lt;br /&gt;
The Launcher&#039;s &#039;&#039;&#039;Workspace&#039;&#039;&#039; submenu carries two stand-alone&lt;br /&gt;
entries (gated on the SSH package being loaded):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH Terminal&#039;&#039;&#039; &amp;amp;mdash; prompts for a target in the form &amp;lt;code&amp;gt;user[:password]@host[:port]&amp;lt;/code&amp;gt; and opens a top-level VT100 terminal connected to it.  No FileBrowser involved &amp;amp;mdash; this is the launcher analogue of the FileBrowserV2 &#039;&#039;&#039;Tools &amp;amp;rarr; SSH Connect...&#039;&#039;&#039; entry.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connection&#039;&#039;&#039; &amp;amp;mdash; prompts for an SFTP target (same URL grammar as the FileBrowserV2 location bar, see [[#From the FileBrowserV2]]) and opens a fresh FileBrowserV2 already navigated to that path.&lt;br /&gt;
&lt;br /&gt;
Both entries honour the URL-embedded password syntax described in&lt;br /&gt;
[[#Password authentication]].&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
&amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only; gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file unencrypted (agent-only mode ignores the passphrase, since the OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to &#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally; a ST/X on the Windows side does not.  Bridging needs a helper like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Password authentication ==&lt;br /&gt;
&lt;br /&gt;
Public-key (with or without ssh-agent) is the recommended path.&lt;br /&gt;
Password authentication is supported as a fallback for the cases&lt;br /&gt;
where keys are not available: legacy hosts, on-the-fly access to a&lt;br /&gt;
test box, scripted access to an account whose owner refuses to add&lt;br /&gt;
your public key.  Keep in mind:&lt;br /&gt;
&lt;br /&gt;
* The plaintext password lives in memory on the ST/X side for the lifetime of the &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; &amp;amp;mdash; treat it like any other in-memory secret.&lt;br /&gt;
* The server still controls which methods it accepts.  If &amp;lt;code&amp;gt;sshd_config&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;PasswordAuthentication no&amp;lt;/code&amp;gt;, no Smalltalk-side configuration can override that.&lt;br /&gt;
* Wire-level the handshake is RFC 4252 §8: the password is sent inside the encrypted SSH transport, never in clear over the network.&lt;br /&gt;
&lt;br /&gt;
=== From a URL ===&lt;br /&gt;
&lt;br /&gt;
Both the FileBrowserV2 location bar and the launcher&#039;s&lt;br /&gt;
&#039;&#039;&#039;Workspace &amp;amp;rarr; SFTP Connection&#039;&#039;&#039; / &#039;&#039;&#039;Workspace &amp;amp;rarr; SSH&lt;br /&gt;
Terminal&#039;&#039;&#039; prompts accept an inline password in the standard&lt;br /&gt;
RFC-3986 userinfo position:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://alice:s3cret@host.example.com/srv/data&lt;br /&gt;
ssh   alice:s3cret@host.example.com:2222&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The parser splits on the &#039;&#039;&#039;last&#039;&#039;&#039; &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; so passwords&lt;br /&gt;
containing &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; still parse; the first &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt;&lt;br /&gt;
inside the userinfo separates user from password.  Passwords&lt;br /&gt;
containing &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; are not supported in this form &amp;amp;mdash;&lt;br /&gt;
use the programmatic API below.&lt;br /&gt;
&lt;br /&gt;
The password is stripped from the printable URL: every place that&lt;br /&gt;
ends up logging or displaying the filename (status line,&lt;br /&gt;
&amp;lt;code&amp;gt;printOn:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nameString&amp;lt;/code&amp;gt;, the breadcrumb path)&lt;br /&gt;
shows the credential-free form&lt;br /&gt;
&amp;lt;code&amp;gt;sftp://alice@host.example.com/...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From code ===&lt;br /&gt;
&lt;br /&gt;
Two equivalent ways to attach a password to an&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;/ literal -- simplest, password is just an ivar&lt;br /&gt;
client := SSH::Client newToHost:&#039;host.example.com&#039; port:22 user:&#039;alice&#039;.&lt;br /&gt;
client password:&#039;s3cret&#039;.&lt;br /&gt;
client connect.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;/ callback -- lazy; the password never lives on the client.&lt;br /&gt;
&amp;quot;/ Useful with an interactive prompt, a keychain lookup, or a&lt;br /&gt;
&amp;quot;/ vault-fetched secret that you do not want long-lived in memory.&lt;br /&gt;
client passwordCallback:[ Dialog requestPassword:&#039;SSH password&#039; ].&lt;br /&gt;
client connect.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The callback wins if both are set.  Both are evaluated lazily&lt;br /&gt;
during &amp;lt;code&amp;gt;#connect&amp;lt;/code&amp;gt;, after publickey/agent attempts have&lt;br /&gt;
been rejected, so a working key always wins over a password when&lt;br /&gt;
both are configured.&lt;br /&gt;
&lt;br /&gt;
=== Authentication order ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;amp;gt;&amp;amp;gt;authenticate&amp;lt;/code&amp;gt; walks every available&lt;br /&gt;
credential in this order, returning on the first one the server&lt;br /&gt;
accepts:&lt;br /&gt;
&lt;br /&gt;
# ssh-agent identities, if &amp;lt;code&amp;gt;#useAgent&amp;lt;/code&amp;gt; was called and the agent has loaded keys.&lt;br /&gt;
# ed25519 private-key seed, if &amp;lt;code&amp;gt;#privateKeyFromFile:&amp;lt;/code&amp;gt; picked one up.&lt;br /&gt;
# RSA private key.&lt;br /&gt;
# ECDSA private key.&lt;br /&gt;
# Password, if &amp;lt;code&amp;gt;#password:&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;#passwordCallback:&amp;lt;/code&amp;gt; was set &#039;&#039;&#039;and&#039;&#039;&#039; the server still advertises &amp;lt;code&amp;gt;password&amp;lt;/code&amp;gt; in its USERAUTH_FAILURE methods list.&lt;br /&gt;
&lt;br /&gt;
Each step is skipped when the server&#039;s last&lt;br /&gt;
&amp;lt;code&amp;gt;USERAUTH_FAILURE&amp;lt;/code&amp;gt; reply dropped the relevant method&lt;br /&gt;
from its allowed list &amp;amp;mdash; we do not bang on&lt;br /&gt;
&amp;lt;code&amp;gt;publickey&amp;lt;/code&amp;gt; after the server stops offering it.  The&lt;br /&gt;
password attempt is only fired when the server still wants&lt;br /&gt;
&amp;lt;code&amp;gt;password&amp;lt;/code&amp;gt;, so a misconfigured client password against a&lt;br /&gt;
key-only server raises a clean&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::AuthenticationError&amp;lt;/code&amp;gt; without an extra useless&lt;br /&gt;
round-trip.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s walkback plus each waiter&#039;s, formatted as plain text.  Use when a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed (e.g. legacy PEM, encrypted-without-agent) — the file is skipped, others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime), no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
[[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every modern OpenSSH does), overwrite is atomic; on the rare server that does not, the receiver is emulated as delete-then-rename and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost three round-trips per directory icon, which made the original tree expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link. Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
&#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer to disk on an open handle.  Available on the low-level&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe, EOF, MNU on nil socket) evicts the dead pool entry, opens a fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP + one SFTP channel per host means N concurrent requests serialise.  Pipelining over multiple SshClients in the pool (preferred), or a transport-level reader process demultiplexing to per-channel inboxes, would let the tree pane keep listing while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (first batch only) + CLOSE — three RTTs per probe; needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style canonicalisation.  (Atomic-overwrite rename is already handled via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension; see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31404</id>
		<title>Remote Access</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31404"/>
		<updated>2026-06-08T14:26:01Z</updated>

		<summary type="html">&lt;p&gt;Sv: password authentication: URL form, code API, auth order; launcher menu entries&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fernzugriff&#039;&#039;&#039; bezeichnet die Möglichkeit, einen entfernten&lt;br /&gt;
Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus&lt;br /&gt;
zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu&lt;br /&gt;
verschieben oder ein Testgerät anzusteuern.  Drei Protokoll-Familien&lt;br /&gt;
sind unterstützt, in absteigender Empfehlungsreihenfolge:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH und SFTP&#039;&#039;&#039; (empfohlen) — verschlüsselte Shell und sichere Dateiübertragung über einen SSH-2-Tunnel.  Reine Smalltalk-Implementierung in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; keine externe Abhängigkeit von OpenSSL oder libssh.  Für alles mit Zugangsdaten oder sensiblen Nutzdaten.&lt;br /&gt;
* &#039;&#039;&#039;Lokale Kommando-Shell&#039;&#039;&#039; — fork + exec auf der lokalen Maschine.  Für die Anbindung lokaler Werkzeuge und für die lokale Seite eines hybriden Workflows.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (veraltet) — Klartext-Terminalsitzung.  Keine Verschlüsselung, Passwörter im Klartext auf der Leitung.  Nur einsetzen, wenn die Gegenstelle keine Alternative bietet.&lt;br /&gt;
&lt;br /&gt;
= SSH und SFTP =&lt;br /&gt;
&lt;br /&gt;
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab&lt;br /&gt;
(RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der&lt;br /&gt;
chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das&lt;br /&gt;
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02).  Zwei Schichten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatischer SSH-Zugriff (entferntes &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY-Shell, Agent-Weiterleitung, ProxyJump-Bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — eine&lt;br /&gt;
&amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;-Unterklasse, die es dem restlichen ST/X&lt;br /&gt;
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale&lt;br /&gt;
Datei.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut:&lt;br /&gt;
zuerst das, was der Anwender sieht und tut, darunter die&lt;br /&gt;
expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails&lt;br /&gt;
für Interessierte.&lt;br /&gt;
&lt;br /&gt;
== Aus dem FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Im Adress-Dropdown eine &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt;-URL einfügen.  Der&lt;br /&gt;
Browser-Tab füllt sich wie bei einem lokalen Pfad.&lt;br /&gt;
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),&lt;br /&gt;
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich&lt;br /&gt;
normal.  Der erste Klick auf einen Host dauert ~200–500 ms&lt;br /&gt;
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte&lt;br /&gt;
Verbindung weiter.&lt;br /&gt;
&lt;br /&gt;
URL-Syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user[:password]@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlt &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;, wird der lokale Login-Name verwendet, Port&lt;br /&gt;
ist standardmäßig 22, Pfad standardmäßig &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.  Das&lt;br /&gt;
optionale &amp;lt;code&amp;gt;:password&amp;lt;/code&amp;gt;-Segment ist das RFC-3986-Userinfo-Passwort&lt;br /&gt;
&amp;amp;mdash; wann es angebracht ist und welche Sicherheitsabwägungen&lt;br /&gt;
damit verbunden sind, beschreibt [[#Passwort-Authentifizierung]].&lt;br /&gt;
Wenn vorhanden, dient es als USERAUTH-Fallback nach den üblichen&lt;br /&gt;
Publickey-/Agent-Versuchen und wird &#039;&#039;&#039;niemals&#039;&#039;&#039; wieder von der&lt;br /&gt;
druckbaren URL-Form ausgegeben &amp;amp;mdash; das Protokollieren des&lt;br /&gt;
Dateinamens leakt also nicht das Credential.&lt;br /&gt;
&lt;br /&gt;
Die Schaltfläche &#039;&#039;&#039;Refresh&#039;&#039;&#039; in der Symbolleiste&lt;br /&gt;
(Pfeil-Kreis-Symbol zwischen &#039;&#039;Forward&#039;&#039; und &#039;&#039;DirectoryUp&#039;&#039;) liest&lt;br /&gt;
Baum und Inhalts-Panel auf Anforderung neu ein.  Funktioniert&lt;br /&gt;
einheitlich für lokale und SFTP-Pfade; bei SFTP wird zusätzlich der&lt;br /&gt;
per-Datei-STAT-Cache geleert, sodass Änderungen, die direkt auf&lt;br /&gt;
der Gegenseite gemacht wurden, sofort sichtbar werden — ohne auf&lt;br /&gt;
den Ablauf der 5-Sekunden-Cache-TTL zu warten.&lt;br /&gt;
&lt;br /&gt;
Der kleine Pfeil neben dem Refresh-Symbol öffnet ein Aufklappmenü&lt;br /&gt;
mit einem einzelnen Kontrollkästchen, &#039;&#039;&#039;Automatic Refresh&#039;&#039;&#039;, das&lt;br /&gt;
den Hintergrund-Task an- bzw. abschaltet, der alle expandierten&lt;br /&gt;
Baumeinträge auf externe Änderungen prüft.  Die Vorgabe richtet&lt;br /&gt;
sich nach der aktuellen Wurzel:&lt;br /&gt;
&lt;br /&gt;
* Lokales Dateisystem &amp;amp;rarr; &#039;&#039;&#039;an&#039;&#039;&#039; (10-Sekunden-Zyklus, entspricht dem bisherigen Verhalten).&lt;br /&gt;
* SFTP &amp;amp;rarr; &#039;&#039;&#039;aus&#039;&#039;&#039;.  Jeder Zyklus kostet einen STAT-Roundtrip pro Kind — für eine Handvoll lokaler Verzeichnisse harmlos, über das Netz schmerzhaft.  Bei Bedarf manuell auf Refresh klicken, um Änderungen zu sehen.&lt;br /&gt;
&lt;br /&gt;
Beim Wechsel zwischen lokalen und SFTP-Wurzeln wird der Schalter&lt;br /&gt;
automatisch umgelegt &amp;amp;mdash; aber nur, sofern man ihn für die&lt;br /&gt;
vorherige Wurzel nicht selbst verstellt hat.  Eine explizite&lt;br /&gt;
Benutzerwahl bleibt über Navigationen hinweg erhalten.&lt;br /&gt;
&lt;br /&gt;
Das Menü &#039;&#039;&#039;Tools&#039;&#039;&#039; im FileBrowserV2 bietet vier Aktionen — die&lt;br /&gt;
drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek&lt;br /&gt;
sichtbar:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — öffnet den Schlüsselerzeugungs-Dialog, siehe [[#Einen SSH-Schlüssel erzeugen]] unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — öffnet ein interaktives VT100-Terminal zu einem entfernten Host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — navigiert diesen Browser-Tab über SFTP auf ein entferntes Dateisystem.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — zeigt Größe, freien Platz und Belegung des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP setzt der Aufruf voraus, daß der Server die Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; ankündigt (jedes moderne OpenSSH&lt;br /&gt;
tut das).  Größen werden in IEC-Binäreinheiten ausgegeben (MiB,&lt;br /&gt;
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1&lt;br /&gt;
liefert, damit ein TB-großes Volume als &#039;&#039;X TiB&#039;&#039; statt&lt;br /&gt;
&#039;&#039;10240 GiB&#039;&#039; erscheint.&lt;br /&gt;
&lt;br /&gt;
== Aus dem Launcher ==&lt;br /&gt;
&lt;br /&gt;
Das Untermenü &#039;&#039;&#039;Workspace&#039;&#039;&#039; im Launcher enthält zwei eigenständige&lt;br /&gt;
Einträge (nur sichtbar bei geladenem SSH-Paket):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH Terminal&#039;&#039;&#039; &amp;amp;mdash; fragt nach einem Ziel der Form &amp;lt;code&amp;gt;user[:password]@host[:port]&amp;lt;/code&amp;gt; und öffnet ein VT100-Terminal als eigenständiges Fenster.  Das ist das Launcher-Pendant zum FileBrowserV2-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; SSH Connect...&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connection&#039;&#039;&#039; &amp;amp;mdash; fragt nach einem SFTP-Ziel (gleiche URL-Grammatik wie in der FileBrowserV2-Adresszeile, siehe [[#Aus dem FileBrowserV2]]) und öffnet einen frischen FileBrowserV2, der bereits dorthin navigiert ist.&lt;br /&gt;
&lt;br /&gt;
Beide Einträge unterstützen die in [[#Passwort-Authentifizierung]]&lt;br /&gt;
beschriebene URL-Form mit eingebettetem Passwort.&lt;br /&gt;
&lt;br /&gt;
== Aus expecco-Aktionen ==&lt;br /&gt;
&lt;br /&gt;
Das Expecco-RemoteAccess-Plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) stellt folgende Testaktionen&lt;br /&gt;
in der expecco-Aktionspalette bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — öffnet eine SSH-Sitzung über das plattformeigene &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;-Binary (PuTTYs &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; unter Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.&lt;br /&gt;
&lt;br /&gt;
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater&lt;br /&gt;
Schlüssel auf dieser Maschine, öffentlicher Teil in der&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des Zielhosts).  Schlüssel&lt;br /&gt;
erzeugen entweder über den Dialog unten oder über&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Plugin fügt zusätzlich eine Settings-Seite hinzu:&lt;br /&gt;
&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039; mit&lt;br /&gt;
einer einzelnen Schaltfläche &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039;, die&lt;br /&gt;
denselben Dialog öffnet.&lt;br /&gt;
&lt;br /&gt;
== Einen SSH-Schlüssel erzeugen ==&lt;br /&gt;
&lt;br /&gt;
=== Der Dialog (FileBrowserV2 / Settings-Seite) ===&lt;br /&gt;
&lt;br /&gt;
Der Dialog fragt alle Parameter in einem Formular ab:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — wird in den erzeugten Schlüssel eingebettet (Voreinstellung &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — schreibt&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (oder wohin man will) samt&lt;br /&gt;
zugehöriger &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;-Datei daneben.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — schreibt die Datei UND übergibt den Schlüssel dem laufenden ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — der Schlüssel lebt nur im Speicher des Agents; nach Agent-Neustart ist er verloren.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — vollständiger Pfad; ausgegraut im Agent-only-Modus.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — leer lässt die On-Disk-Datei unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten Schlüssel transportiert).&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;Generate&#039;&#039;&#039; wird die Public-Key-Zeile (dieselbe&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt;-Zeichenfolge, die&lt;br /&gt;
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum&lt;br /&gt;
direkten Einfügen in die &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des&lt;br /&gt;
Zielhosts.&lt;br /&gt;
&lt;br /&gt;
=== Aus einem Workspace ===&lt;br /&gt;
&lt;br /&gt;
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; einen reinen Smalltalk-Schlüsselgenerator&lt;br /&gt;
bereit, dessen Ausgabe bit-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt; ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Passphrase-verschlüsselt auf Platte speichern&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ UND in den laufenden Agent laden&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll&lt;br /&gt;
interoperabel (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; rekonstruiert den&lt;br /&gt;
öffentlichen Schlüssel, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; ändert&lt;br /&gt;
die Passphrase usw.).&lt;br /&gt;
&lt;br /&gt;
=== Mit den Shell-Werkzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der klassische Weg funktioniert weiterhin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ssh-agent vorbereiten ==&lt;br /&gt;
&lt;br /&gt;
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien&lt;br /&gt;
deutlich vorzuziehen: er hält verschlüsselte private Schlüssel&lt;br /&gt;
einmal pro Sitzung entsperrt und kann Identitäten verwalten&lt;br /&gt;
(hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X&lt;br /&gt;
nie direkt sehen soll.&lt;br /&gt;
&lt;br /&gt;
ST/X erkennt den Agent-Pfad automatisch, sobald&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;zum Zeitpunkt des Starts von stx&#039;&#039;&#039;&lt;br /&gt;
in der Prozessumgebung gesetzt ist.  Eine spätere Zuweisung aus&lt;br /&gt;
einem Workspace nützt nichts.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Die meisten Desktop-Distributionen starten einen Agent automatisch&lt;br /&gt;
beim Login (gnome-keyring unter GNOME, ssh-agent.service unter&lt;br /&gt;
systemd, KWallet unter KDE).  Prüfen im Terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh oder ähnlich&lt;br /&gt;
ssh-add -l             # listet geladene Identitäten&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # eigene laden, falls nicht da&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei&lt;br /&gt;
aufnehmen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc oder ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X muss aus einer Shell gestartet werden, die diese rc bereits&lt;br /&gt;
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die&lt;br /&gt;
Variable nicht.  Empfehlung: ein kleines Wrapper-Skript unter&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt;, das die rc sourcet und dann stx&lt;br /&gt;
startet.&lt;br /&gt;
&lt;br /&gt;
Die Settings-Seite (&#039;&#039;&#039;Extras → Settings → Plugins → Remote&lt;br /&gt;
Access — SSH Keys&#039;&#039;&#039;) zeigt an, ob das laufende Image einen&lt;br /&gt;
Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Permanente Einrichtung via systemd ====&lt;br /&gt;
&lt;br /&gt;
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-&lt;br /&gt;
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den&lt;br /&gt;
meisten Distros mit dem Paket &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
ausgelieferte Per-User-systemd-Unit aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; in der Shell-rc auf den&lt;br /&gt;
User-Service-Socket zeigen lassen (ersetzt das&lt;br /&gt;
&amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;-Snippet oben):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Um den manuellen &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt;-Schritt zu sparen, kann&lt;br /&gt;
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.&lt;br /&gt;
In &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt; eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und&lt;br /&gt;
übergibt den entsperrten Schlüssel an den Agent; weitere&lt;br /&gt;
Verbindungen nutzen die gespeicherte Identität ohne Prompt.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit.&lt;br /&gt;
Einmalige Einrichtung:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Dienste&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) als Administrator öffnen.&lt;br /&gt;
# &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039; suchen, Starttyp auf &#039;&#039;&#039;Automatisch&#039;&#039;&#039; setzen, &#039;&#039;&#039;Starten&#039;&#039;&#039; anklicken.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Prüfen: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), nicht auf einem&lt;br /&gt;
Unix-Socket.  ST/X unterstützt beide Transporte, jedoch setzt das&lt;br /&gt;
Windows-ssh-add &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; selbst.&lt;br /&gt;
Daher einmalig systemweit setzen:&lt;br /&gt;
&lt;br /&gt;
# {{Key|Win}} drücken → &amp;quot;Umgebungsvariablen&amp;quot; → „Systemumgebungs- variablen bearbeiten&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Umgebungsvariablen&#039;&#039;&#039; → unter &#039;&#039;&#039;Benutzervariablen&#039;&#039;&#039;, &#039;&#039;&#039;Neu&#039;&#039;&#039; klicken.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Wert: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ab- und wieder anmelden (oder stx neu starten), damit die neue Umgebung übernommen wird.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell-Schnelleinrichtung ====&lt;br /&gt;
&lt;br /&gt;
Derselbe Aufbau aus einer &#039;&#039;&#039;Administrator-PowerShell&#039;&#039;&#039; heraus,&lt;br /&gt;
z.B. für Skripte oder unbeaufsichtigte Bereitstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Agent jetzt und bei jedem Neustart starten (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung&lt;br /&gt;
(z.B. Einzelsitzung) die &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt;-Zeile weglassen&lt;br /&gt;
und nur &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt; ausführen.  Die&lt;br /&gt;
env-var-Zeile lässt sich ebenfalls weglassen, wenn&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; nur in der aktuellen Shell gebraucht&lt;br /&gt;
wird — dann statt der &amp;lt;code&amp;gt;[Environment]&amp;lt;/code&amp;gt;-Variante&lt;br /&gt;
&amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Auf stark abgespeckten Windows-Installationen ist der&lt;br /&gt;
ssh-agent-Dienst eventuell nicht vorhanden.  Einmalig nachrüsten&lt;br /&gt;
über &#039;&#039;&#039;Einstellungen → Apps → Optionale Features → OpenSSH-&lt;br /&gt;
Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative Agenten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — eigenes Protokoll; von ST/X&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Agent&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; unterstützt.  Schlüssel zu&lt;br /&gt;
OpenSSH migrieren.&lt;br /&gt;
* &#039;&#039;&#039;Git für Windows ssh-agent&#039;&#039;&#039; — funktioniert;&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; auf den dort veröffentlichten Socket&lt;br /&gt;
zeigen lassen.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — ein ST/X innerhalb der WSL sieht den WSL-eigenen Agent normal; ein ST/X auf der Windows-Seite nicht.  Eine Brücke per &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt; ist möglich.&lt;br /&gt;
&lt;br /&gt;
Prüfung über die Settings-Seite&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
die Anzeige dort meldet, ob das laufende Image den Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Windows-OpenSSH speichert agent-geladene Schlüssel &#039;&#039;&#039;nicht&#039;&#039;&#039;&lt;br /&gt;
über Agent-Neustarts hinweg.  Um nicht nach jedem Reboot manuell&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; aufrufen zu müssen, dieselbe Lazy-Load-&lt;br /&gt;
Konfiguration in &amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;&lt;br /&gt;
eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent&lt;br /&gt;
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige&lt;br /&gt;
Sitzung weiter.&lt;br /&gt;
&lt;br /&gt;
== Passwort-Authentifizierung ==&lt;br /&gt;
&lt;br /&gt;
Empfohlen ist Public-Key-Authentifizierung (mit oder ohne&lt;br /&gt;
ssh-agent).  Passwort-Authentifizierung ist als Fallback gedacht,&lt;br /&gt;
wenn keine Schlüssel verfügbar sind: Altsysteme, Ad-hoc-Zugriff&lt;br /&gt;
auf einen Testserver, Skripte gegen ein Konto, dessen Besitzer den&lt;br /&gt;
Public Key nicht hinterlegen möchte.  Zu beachten:&lt;br /&gt;
&lt;br /&gt;
* Das Klartext-Passwort liegt auf ST/X-Seite für die Lebensdauer des &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; im Speicher &amp;amp;mdash; entsprechend behandeln wie jedes andere In-Memory-Geheimnis.&lt;br /&gt;
* Der Server entscheidet, welche Methoden er akzeptiert.  Steht in &amp;lt;code&amp;gt;sshd_config&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;PasswordAuthentication no&amp;lt;/code&amp;gt;, kann keine Smalltalk-seitige Einstellung das überschreiben.&lt;br /&gt;
* Auf Drahtebene entspricht der Vorgang RFC 4252 §8: das Passwort wandert innerhalb der verschlüsselten SSH-Transportschicht, niemals im Klartext über das Netz.&lt;br /&gt;
&lt;br /&gt;
=== Aus einer URL ===&lt;br /&gt;
&lt;br /&gt;
Sowohl die FileBrowserV2-Adressleiste als auch die Launcher-Dialoge&lt;br /&gt;
&#039;&#039;&#039;Workspace &amp;amp;rarr; SFTP Connection&#039;&#039;&#039; / &#039;&#039;&#039;Workspace &amp;amp;rarr; SSH&lt;br /&gt;
Terminal&#039;&#039;&#039; akzeptieren ein eingebettetes Passwort an der&lt;br /&gt;
standardmäßigen RFC-3986-Userinfo-Position:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://alice:s3cret@host.example.com/srv/data&lt;br /&gt;
ssh   alice:s3cret@host.example.com:2222&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Parser splittet am &#039;&#039;&#039;letzten&#039;&#039;&#039; &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt;, sodass&lt;br /&gt;
Passwörter mit enthaltenem &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; dennoch korrekt geparst&lt;br /&gt;
werden; der erste &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; im Userinfo-Teil trennt Benutzer&lt;br /&gt;
und Passwort.  Passwörter, die selbst ein &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; enthalten,&lt;br /&gt;
werden in dieser Form nicht unterstützt &amp;amp;mdash; dafür die&lt;br /&gt;
programmatische API unten verwenden.&lt;br /&gt;
&lt;br /&gt;
Das Passwort wird aus der druckbaren URL entfernt: jede Stelle, die&lt;br /&gt;
am Ende den Dateinamen ausgibt (Statuszeile,&lt;br /&gt;
&amp;lt;code&amp;gt;printOn:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nameString&amp;lt;/code&amp;gt;, die Breadcrumb-Leiste)&lt;br /&gt;
zeigt die credential-freie Form&lt;br /&gt;
&amp;lt;code&amp;gt;sftp://alice@host.example.com/...&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Aus Code ===&lt;br /&gt;
&lt;br /&gt;
Zwei äquivalente Wege, einem &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; ein Passwort&lt;br /&gt;
mitzugeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;/ Literal -- am einfachsten, Passwort ist nur ein Ivar&lt;br /&gt;
client := SSH::Client newToHost:&#039;host.example.com&#039; port:22 user:&#039;alice&#039;.&lt;br /&gt;
client password:&#039;s3cret&#039;.&lt;br /&gt;
client connect.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;/ Callback -- lazy; das Passwort lebt nie auf dem Client.&lt;br /&gt;
&amp;quot;/ Praktisch für interaktive Abfrage, Keychain-Lookup oder ein&lt;br /&gt;
&amp;quot;/ Vault-gespeichertes Geheimnis, das nicht langlebig im Speicher&lt;br /&gt;
&amp;quot;/ liegen soll.&lt;br /&gt;
client passwordCallback:[ Dialog requestPassword:&#039;SSH-Passwort&#039; ].&lt;br /&gt;
client connect.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sind beide gesetzt, gewinnt der Callback.  Beide werden lazy&lt;br /&gt;
während &amp;lt;code&amp;gt;#connect&amp;lt;/code&amp;gt; ausgewertet, nachdem die&lt;br /&gt;
Publickey-/Agent-Versuche abgelehnt wurden &amp;amp;mdash; ein&lt;br /&gt;
funktionierender Schlüssel schlägt also immer ein parallel&lt;br /&gt;
konfiguriertes Passwort.&lt;br /&gt;
&lt;br /&gt;
=== Reihenfolge der Authentifizierungsversuche ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;amp;gt;&amp;amp;gt;authenticate&amp;lt;/code&amp;gt; geht jedes verfügbare&lt;br /&gt;
Credential der Reihe nach durch und kehrt beim ersten zurück, das&lt;br /&gt;
der Server akzeptiert:&lt;br /&gt;
&lt;br /&gt;
# ssh-agent-Identitäten, sofern &amp;lt;code&amp;gt;#useAgent&amp;lt;/code&amp;gt; aufgerufen wurde und der Agent Schlüssel geladen hat.&lt;br /&gt;
# ed25519-Privatschlüssel-Seed, sofern &amp;lt;code&amp;gt;#privateKeyFromFile:&amp;lt;/code&amp;gt; einen geladen hat.&lt;br /&gt;
# RSA-Privatschlüssel.&lt;br /&gt;
# ECDSA-Privatschlüssel.&lt;br /&gt;
# Passwort, sofern &amp;lt;code&amp;gt;#password:&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;#passwordCallback:&amp;lt;/code&amp;gt; gesetzt ist &#039;&#039;&#039;und&#039;&#039;&#039; der Server &amp;lt;code&amp;gt;password&amp;lt;/code&amp;gt; in seiner USERAUTH_FAILURE-Methodenliste weiterhin anbietet.&lt;br /&gt;
&lt;br /&gt;
Jeder Schritt wird übersprungen, wenn die letzte&lt;br /&gt;
&amp;lt;code&amp;gt;USERAUTH_FAILURE&amp;lt;/code&amp;gt;-Antwort des Servers die jeweilige&lt;br /&gt;
Methode aus der erlaubten Liste gestrichen hat &amp;amp;mdash; auf&lt;br /&gt;
&amp;lt;code&amp;gt;publickey&amp;lt;/code&amp;gt; wird also nicht weiter herumgehämmert,&lt;br /&gt;
sobald der Server damit aufhört.  Der Passwortversuch läuft nur,&lt;br /&gt;
wenn der Server &amp;lt;code&amp;gt;password&amp;lt;/code&amp;gt; noch verlangt; ein falsch&lt;br /&gt;
konfiguriertes Passwort gegen einen reinen Schlüssel-Server erzeugt&lt;br /&gt;
also einen sauberen &amp;lt;code&amp;gt;SSH::AuthenticationError&amp;lt;/code&amp;gt; ohne&lt;br /&gt;
zusätzlichen nutzlosen Roundtrip.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Alle Stellschrauben sind klassenseitig auf&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; erreichbar:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Voreinstellung !! Steuert&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 Min) || Wie lange&lt;br /&gt;
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.&lt;br /&gt;
Liegt knapp unter dem typischen&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; des sshd,&lt;br /&gt;
damit wir uns recyceln, bevor der Server uns mit TCP-RESET&lt;br /&gt;
trennt.  &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; setzt auf Voreinstellung zurück.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Maximales Alter (s)&lt;br /&gt;
eines gecachten STAT, bevor &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; neu am&lt;br /&gt;
Server fragt.  Eltern-listDir stempelt ohnehin frische Attribute&lt;br /&gt;
auf alle Kinder, daher zahlt das Navigieren im offenen&lt;br /&gt;
Verzeichnis das TTL nicht.  &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; schaltet den Cache&lt;br /&gt;
ab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (Aktion) || Reißt jede&lt;br /&gt;
gepoolte Verbindung ab.  Nützlich nach einem bekannt schlechten&lt;br /&gt;
Netzereignis, vor einem bewussten Identitätswechsel oder zum&lt;br /&gt;
sauberen Image-Shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnose ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; über das Untermenü „Status&amp;quot; des&lt;br /&gt;
Launchers öffnen.  Der pro-Host-SFTP-Mutex erscheint als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;, der pool-weite Mutex als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Per Rechtsklick:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — schreibt den Walkback des letzten Eigners samt aller Waiter als Text in die Zwischenablage.  Unverzichtbar, wenn ein Prozess in&lt;br /&gt;
&amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; innerhalb von&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; klemmt.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — die ganze Tabelle, ideal für eine E-Mail-Diagnose.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS über den Wait-for-Graph, meldet Zyklen.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
Interessante Ereignisse werden über &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; geloggt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei automatischem Reconnect nach toter Verbindung.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei Idle-Verdrängung eines Pool-Eintrags.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; wenn eine SSH-Schlüsseldatei nicht geparst werden konnte — die Datei wird übersprungen.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nur SFTP v3.&#039;&#039;&#039;  Kein SETSTAT (kein entferntes chmod / chown / utime), kein SSH_FXP_READLINK exponiert (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; liefert immer &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; die normale stat-Info).  Einige&lt;br /&gt;
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische&lt;br /&gt;
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host.&#039;&#039;&#039;  Zwei gleichzeitige Operationen am selben Host stehen am Host-Mutex an.  Siehe [[#Ausblick]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt;-Fallback hat ein TOCTOU-Fenster.&#039;&#039;&#039; Bei Servern, die &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; ankündigen (jedes moderne OpenSSH tut das), ist das Überschreiben atomar. Beim seltenen Server, der das nicht tut, wird auf Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich dazwischenschieben.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; ist eine Heuristik.&#039;&#039;&#039; Liefert immer &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (die genaue Antwort würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).&lt;br /&gt;
&lt;br /&gt;
== Implementierungsdetails ==&lt;br /&gt;
&lt;br /&gt;
Für Leser, die die Architektur verstehen wollen.  Fünf Klassen,&lt;br /&gt;
von oben nach unten:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Aufgabe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename-Unterklasse, die&lt;br /&gt;
öffentliche API.  Bildet &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt;-URLs auf&lt;br /&gt;
entfernte Dateien ab und stellt &amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; usw. bereit.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3-Protokoll&lt;br /&gt;
(Request/Response-Codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Wird von SftpFilename angesteuert.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH-Kanal-Multiplexer (CHANNEL_OPEN,&lt;br /&gt;
DATA, EOF, CLOSE, WINDOW_ADJUST).  Eine logische Sitzung pro&lt;br /&gt;
Channel-Instanz.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-Level-SSH-Client: öffnet den&lt;br /&gt;
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und&lt;br /&gt;
verteilt anschließend Kanäle.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Drahtschicht.  Banner- und&lt;br /&gt;
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq /&lt;br /&gt;
recvSeq, Heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH-SFTP-Erweiterungen ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst&lt;br /&gt;
minimal gehalten.  OpenSSH bringt einen offenen&lt;br /&gt;
Erweiterungsmechanismus mit: der Server listet im&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;-Reply die Erweiterungsnamen auf, die&lt;br /&gt;
er versteht, und der Client ruft sie über&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt;-Pakete mit dem&lt;br /&gt;
Erweiterungsnamen als erstem String auf.  Jede Erweiterung wird&lt;br /&gt;
über &amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;&lt;br /&gt;
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie&lt;br /&gt;
nicht ankündigt.&lt;br /&gt;
&lt;br /&gt;
Der Stack nutzt heute vier OpenSSH-Erweiterungen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomares rename-mit-Überschreiben.  Wird automatisch von&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt; aufgegriffen; die&lt;br /&gt;
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum&lt;br /&gt;
Einsatz, die die Erweiterung nicht haben.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — Erzeugt einen POSIX-Hardlink. Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX-&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-typische Dateisystem-Statistik.&lt;br /&gt;
Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;;&lt;br /&gt;
das Ergebnis ist form-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;, sodass Aufrufer&lt;br /&gt;
lokale und entfernte Pfade einheitlich behandeln können.&lt;br /&gt;
Treibt den Menü-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; an,&lt;br /&gt;
der am Anfang dieser Seite beschrieben ist.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — schreibt den serverseitigen Schreibpuffer eines geöffneten Handles auf Platte.  Liegt als&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt; bereit; noch nicht&lt;br /&gt;
in eine &amp;quot;Durable-Write&amp;quot;-API auf Filename-Ebene eingebunden.&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden OpenSSH-Erweiterungen&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
werden in der angekündigten Liste erkannt, aber nicht auf&lt;br /&gt;
Filename-Ebene gekapselt — es gibt dafür noch keinen&lt;br /&gt;
Filename-seitigen Aufrufer.&lt;br /&gt;
&lt;br /&gt;
=== Verbindungs-Pooling ===&lt;br /&gt;
&lt;br /&gt;
Alle &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt;-Instanzen, die auf dasselbe Tripel&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; zeigen, teilen sich einen&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; samt einem &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Der Pool ist klassenseitig und wird von einem einzigen&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt; bewacht:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy-Aufbau&#039;&#039;&#039; — TCP + KEX + userauth + SFTP-INIT laufen erst beim ersten SFTP-Aufruf, nicht in &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host&#039;&#039;&#039; — SFTP-Anfragen an einen bestimmten Host werden durch einen &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; mit dem Namen &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; serialisiert (sichtbar im SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle-Verdrängung&#039;&#039;&#039; — ein Pool-Eintrag, der länger als&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt; ungenutzt liegt, wird beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet.&lt;br /&gt;
* &#039;&#039;&#039;Automatischer Reconnect&#039;&#039;&#039; — ein Fehler auf Transportebene (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den Pool-Eintrag, öffnet einen frischen Client und wiederholt die Anfrage &#039;&#039;&#039;einmal&#039;&#039;&#039;.  Anwendungsfehler aus SFTP-STATUS-Antworten werden sofort durchgereicht.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
&lt;br /&gt;
Geplant, aber noch nicht umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-Channel-Parallelität pro Host&#039;&#039;&#039; — aktuell bedeutet eine TCP- plus eine SFTP-Verbindung pro Host, dass N gleichzeitige Anfragen serialisieren.  Pipelining über mehrere SshClients im Pool (bevorzugt) oder ein transport-seitiger Reader-Prozess, der eingehende Pakete in Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel erlauben, weiter aufzulisten, während das Inhalts-Panel eine große Datei liest.&lt;br /&gt;
* &#039;&#039;&#039;Genaues &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen kann.&lt;br /&gt;
* &#039;&#039;&#039;SFTP-v5/v6-Aushandlung&#039;&#039;&#039; für erweiterte Attribute und FTP-artige Kanonisierung.  (Atomares Überschreibungs-rename ist bereits über die OpenSSH-Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; abgedeckt; siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]].)&lt;br /&gt;
&lt;br /&gt;
= Kommando-Shell =&lt;br /&gt;
&lt;br /&gt;
Lokale Kommando-Shell auf dieser expecco-Maschine.  Typische&lt;br /&gt;
Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm,&lt;br /&gt;
Brücke zwischen entferntem Workflow und lokalem Tool.&lt;br /&gt;
&lt;br /&gt;
Das RemoteAccess-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des&lt;br /&gt;
expecco-Prozesses.  Ausgaben gehen in das expecco-Log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warnung]] &#039;&#039;&#039;Telnet ist ein veraltetes&lt;br /&gt;
Protokoll ohne Verschlüsselung.&#039;&#039;&#039; Passwörter werden im Klartext&lt;br /&gt;
über die Leitung übertragen; jeder im Netzpfad kann sie lesen.&lt;br /&gt;
Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative&lt;br /&gt;
bietet (typisch: alte Industriesteuerungen, Laborgeräte,&lt;br /&gt;
eingebettete Messgeräte ohne SSH-Stack).  Für alles andere&lt;br /&gt;
[[#SSH und SFTP]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Das expecco-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (interne Demo)&lt;br /&gt;
&lt;br /&gt;
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler&lt;br /&gt;
8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für&lt;br /&gt;
Terminal-Optionen.  Verbindungsaufbau zum Ziel-Host:Port; nach&lt;br /&gt;
optionalem In-Band-Login können beide Seiten Daten senden.&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY, Agent-Weiterleitung, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks.&lt;br /&gt;
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack als HTTPS-Transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Netz]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31335</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31335"/>
		<updated>2026-05-29T07:39:47Z</updated>

		<summary type="html">&lt;p&gt;Sv: add performance entry for log-archive load speedup&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports both &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; or &#039;&#039;&#039;Llama&#039;&#039;&#039; as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via [[Tools_FileBrowser/en|FileBrowser]])&lt;br /&gt;
* Feature: public/private keypair generation via a [[Tools_FileBrowser/en|FileBrowser]] menu (for easy SSH setup)&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed the [[Number_API_Functions|Number]] stack (see also in [[Numeric_Limits/en| Numeric Limits]]):&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. and type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan). Now all test cases produce a result within the precision limits of their type&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]. &lt;br /&gt;
* Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
* Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
* Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Performance: speedup of cryptographic algorithms (affects key generation and other)&lt;br /&gt;
* Performance: tuned loading of stored ets/elf files (30-40% speedup)&lt;br /&gt;
* Performance: further speedup when loading test-result archives that embed large execution logs — typical load is roughly a third faster again&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=FAQ_on_Bridges/en&amp;diff=31331</id>
		<title>FAQ on Bridges/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=FAQ_on_Bridges/en&amp;diff=31331"/>
		<updated>2026-05-27T13:48:26Z</updated>

		<summary type="html">&lt;p&gt;Sv: update SSL section: client cert in prefs, load/inspect/clear UI, chain validation on load&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Why Bridged Actions and not Script Actions? ==&lt;br /&gt;
&lt;br /&gt;
Script actions will start the language interpreter anew for every such action. Thus, no internal state can be held and transferred from one such action to another. Especially, it is not possible to open a communication channel on one script action, pass it back to expecco, and use it with different followup script actions (i.e. actions like &amp;quot;&#039;&#039;open-port&#039;&#039;&amp;quot; / &amp;quot;&#039;&#039;send message&#039;&#039;&amp;quot; / &amp;quot;&#039;&#039;receive message&#039;&#039;&amp;quot; / &amp;quot;&#039;&#039;close port&#039;&#039;&amp;quot; etc.).&lt;br /&gt;
&lt;br /&gt;
For this, it is required to call individual API-entries inside the bridge code, and return handles from the bridge to expecco, which can later be passed to other API entries.&amp;lt;br&amp;gt;This of course only makes sense, if the interpreter stays active during the lifetime of the connection.&lt;br /&gt;
&lt;br /&gt;
On the other hand, script actions are easier to use if a self contained program or app is to be started, or which performs a single processing action or which stays alive for longer, serving a socket or database. In any such case, there is no need to exchange individual data objects (such as handles) with expecco. It may however interact with expecco through other communication channels, such as sockets, RPC calls, SOAP interface or stdin/stdout text ports.&lt;br /&gt;
&lt;br /&gt;
Thus, you will typically use script actions to start server applications and bridged actions to call individual functions of a framework.&lt;br /&gt;
&lt;br /&gt;
== Which Languages are Supported ==&lt;br /&gt;
&lt;br /&gt;
By the time this chapter was written, bridged code execution is supported for:&lt;br /&gt;
* Java (using either Groovy or Jython as &amp;quot;&#039;&#039;glue&#039;&#039;&amp;quot; or directly using proxy objects in expecco)&lt;br /&gt;
* Python (both Python 2.7 and Python 3.x)&lt;br /&gt;
* .NET (using IronPython as &amp;quot;&#039;&#039;glue&#039;&#039;&amp;quot; or directly via proxy objects)&lt;br /&gt;
* NodeJS (i.e. JavaScript)&lt;br /&gt;
* C/C++ (Root/Cling is being developed currently)&lt;br /&gt;
* Smalltalk (Smalltalk/X and VisualWorks are currently supported; VisualAge may come in the near future, if there is sufficient customer interest)&lt;br /&gt;
* Ruby&lt;br /&gt;
Plans are to support Dart and Scheme in the future.&lt;br /&gt;
&lt;br /&gt;
== How are Bridges Started ==&lt;br /&gt;
&lt;br /&gt;
Bridges on the local machine are usually automatically started by expecco itself, when the first bridged action is executed (and stays alive, until expecco is terminated, or bridge connections are closed via the menu or via an expecco action block). Some language interpreters may take a few seconds to come up, so the first such action will execute relatively slow compared to later actions. You can add a dummy (empty) bridged action to your startup actions (project&#039;s postLoad action) to prepare the bridged interpreter and have it startup in parallel. &lt;br /&gt;
&lt;br /&gt;
Bridges on other machines, or additional bridges on the local machine must be started by executing a bridge start action block or simply by executing a shell/batch action to call the corresponding language interpreter (python, node, etc.). On Windows, a powershell action can be used for remote execution (given that your Windows security settings allow that). On Unix, a shell action executin a remote shell / ssh command could be used.&lt;br /&gt;
&lt;br /&gt;
== Who Initiates the Connection ==&lt;br /&gt;
&lt;br /&gt;
Normally, expecco opens a port and tells the bridge (via command line argument) to which port to connect. Depending on the setup of your network and firewall, it may sometimes be required to reverse this, and let the bridge open a port and expecco connect to it. &lt;br /&gt;
&lt;br /&gt;
For this, some bridges support command line arguments (&amp;quot;--server&amp;quot; and &amp;quot;--port&amp;quot;) to specify this behavior. Details are found in the individual bridge documentation pages.&lt;br /&gt;
&lt;br /&gt;
== Ports Used for Bridge Communication ==&lt;br /&gt;
&lt;br /&gt;
Unless ports are configured in the expecco settings,&lt;br /&gt;
the following default ports are used (bridges typically listen on or connect to this port, unless an explicit &amp;quot;--port&amp;quot; argument is given):&lt;br /&gt;
&lt;br /&gt;
 Python      8677 , 8678 (debug) &lt;br /&gt;
   Python2     8679 , 8680 (debug)&lt;br /&gt;
   Python3     8681 , 8682 (debug)&lt;br /&gt;
 Jython      8777 , 8778 (debug)&lt;br /&gt;
 IronPython  8787 , 8788 (debug)&lt;br /&gt;
 Node        8577 , 8578 (debug)&lt;br /&gt;
 Electron    8588 , 8589 (debug)&lt;br /&gt;
 [[Embedded_Systems_C_Bridge_API |CBridge]]     8855 (also for Root/Cling)&lt;br /&gt;
 Smalltalk   8877&lt;br /&gt;
 VASmalltalk 8879&lt;br /&gt;
 VWSmalltalk 8881&lt;br /&gt;
 Dart        8885&lt;br /&gt;
 Ruby        8977&lt;br /&gt;
 Scheme      8599&lt;br /&gt;
&lt;br /&gt;
Note: for some bridges, two connections are used, the debug port being used by the debugger to inspect data and to support breakpoints, single stepping etc. &lt;br /&gt;
&amp;lt;br&amp;gt;Note: expecco will try successive alternative ports, if the default port happens to be already in use.&lt;br /&gt;
&lt;br /&gt;
Debugging is not supported on all bridges (eg. the C-bridge does not).&lt;br /&gt;
&lt;br /&gt;
== What are Proxy Objects ==&lt;br /&gt;
These are placeholder objects inside expecco, which will look like regular Smalltalk (or JavaScript) objects inside expecco, but will forward any call via the socket ower to the bridge partner. &lt;br /&gt;
&lt;br /&gt;
Thus, they can be used transparently inside Smalltalk and JavaScript elementary actions, performing whatever is implemented in the remote side.&lt;br /&gt;
&lt;br /&gt;
For example, given a Java bridge connection named &amp;quot;bridge&amp;quot;, you can instantiate a remote object there from within your local JavaScript code with:&lt;br /&gt;
 var remoteArrayListClass, myList;&lt;br /&gt;
 remoteArrayListClass = bridge.resolveType(&amp;quot;java.util.ArrayList&amp;quot;);&lt;br /&gt;
 myList = new remoteArrayListClass(10);&lt;br /&gt;
 myList.add(&amp;quot;hello&amp;quot;);&lt;br /&gt;
 ...&lt;br /&gt;
in a Smalltalk action, the code is similar:&lt;br /&gt;
 |remoteArrayList myList|&lt;br /&gt;
 remoteArrayListClass := bridge resolveType:&#039;java.util.ArrayList&#039;.&lt;br /&gt;
 myList := remoteArrayListClass new:10.&lt;br /&gt;
 myList add:&#039;hello&#039;.&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
This works without any remote code injection and is typically a bit faster than via Groovy. However, the language syntax is the local expecco syntax, which might be inconvenient to hard-core Java programmers (and the same is true for proxies to other language&#039;s bridge objects).&lt;br /&gt;
&lt;br /&gt;
Remote proxy objects are also returned by the &amp;quot;&amp;lt;code&amp;gt;makeRef&amp;lt;/code&amp;gt;&amp;quot; API as described in the API documentation, and when remote objects are inspected in the expecco data inspector window.&lt;br /&gt;
&lt;br /&gt;
== What can I do if a Bridge is Dead(locked) ==&lt;br /&gt;
&lt;br /&gt;
The code executed in the bridge may run into an endless loop (for example, if your elementary code contains a bug), or when it calls a function which does not return.&lt;br /&gt;
As a consequence, the corresponding elementary action will not finish.&lt;br /&gt;
&lt;br /&gt;
Try to stop or abort the execution via the corresponding toolbar function (in the expecco editor page).&lt;br /&gt;
Even though the corresponding expecco action has now finished (i.e. expecco will no longer wait for the action&#039;s return value and status), a problem might be reported when expecco is about to call another action inside that bridge: the bridge will still be in its loop, and the bridge will therefore not respond and expecco will report that the bridge is no longer answering.&lt;br /&gt;
&lt;br /&gt;
You now have to kill the bridge, and start a new one, with the undesired consequence of loosing any state inside the previous bridge incarnation. Especially, any connections in the previous bridge are now lost.&lt;br /&gt;
&lt;br /&gt;
To kill the bridge, perform one of the following:&lt;br /&gt;
* click the &amp;quot;&#039;&#039;Terminate Bridge&#039;&#039;&amp;quot; toolbar button in the &amp;quot;Test/Demo&amp;quot; tab.&amp;lt;br&amp;gt;This will terminate that language&#039;s bridges&lt;br /&gt;
* select &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Debugging&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Close all Bridge Connections&#039;&#039;&amp;quot;&amp;lt;br&amp;gt;This will terminate all running bridges (maybe this is not what you want)&lt;br /&gt;
* select &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Debugging&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;OS Process Monitor&#039;&#039;&amp;quot; to get a list of all OS processes which have been started by expecco, select the one to terminate and choose &amp;quot;&#039;&#039;Terminate&#039;&#039;&amp;quot; from the context menu.&lt;br /&gt;
* select and terminate the bridge process in the Task Manager (Windows) or find its processID with the &amp;quot;ps&amp;quot; command and terminate it via the &amp;quot;kill&amp;quot; command (Unix)&lt;br /&gt;
&lt;br /&gt;
If the bridge was not originally started by expecco (eg. if it is a remote bridge, which was started automatically or by a remote command), you have to log into that remote machine and terminate the bridge there.&lt;br /&gt;
&lt;br /&gt;
In a production system, you may add time limits to actions which might suffer from locked bridges, and add a bridge-terminate action (found in the Standard Library) to be triggered via the exception pin of the time-controlled action.&lt;br /&gt;
&lt;br /&gt;
== I got an Object (Reference) from a Bridge but Access to its Fields is Slow ==&lt;br /&gt;
Be reminded ([[#What_are_Proxy_Objects |see above]]), that when an object (reference) is returned from a bridge to expecco, a proxy (placeholder object) is created inside expecco, which is what appears at the output pin.&lt;br /&gt;
This proxy object will intercept any calls to it and forward them to the real object inside the bridge, then wait for a response (the return value) and encode that again as a proxy.&lt;br /&gt;
&lt;br /&gt;
Thus, every such operation involves a round trip which is typically in the order of milliseconds (if the bridge is on a remote machine, and additional routers/switches are involved, the round trip times may even be in the 10-millisecond range).&lt;br /&gt;
These times can easily add up to seconds, for example if you enumerate a remote collection with many elements. &lt;br /&gt;
&lt;br /&gt;
Possible solutions to that problem:&lt;br /&gt;
* install the code which enumerates the object inside the bridge (i.e. define another elementary action or require/import a piece of code which contains this functionality. Then call this code which runs completely inside the bridge.&lt;br /&gt;
* pass the object&#039;s encoding (for example as JSON) and decode it on the expecco side for the enumeration. This one call will then probably run much slower, but further processing (enumeration of elements) is much faster. This is the way to go, if bulk data has been collected inside the bridge, which has to be analyzed inside expecco afterwards.&amp;lt;br&amp;gt;Be aware though, that the object inside expecco is effectively a &amp;quot;copy&amp;quot; of the object; if the object will change inside the bridge, expecco will still present the old state.&lt;br /&gt;
&lt;br /&gt;
== I get Timeouts - how can I change the Defaults ? ==&lt;br /&gt;
There is currently no dialog to change the default settings (except for the CBridge in v23.1). &lt;br /&gt;
&lt;br /&gt;
However, the default values which control the timeouts can be changed via Smalltalk expressions (or corresponding JavaScript expressions).&lt;br /&gt;
&amp;lt;br&amp;gt;To set a common default for all Python, CBridge and NodeJS bridge&amp;lt;br&amp;gt;In Smalltalk syntax:&lt;br /&gt;
 SimpleBridge connectTimeout: &#039;&#039;seconds&#039;&#039;.     &lt;br /&gt;
 SimpleBridge defineAckTimeoutMS: &#039;&#039;millis&#039;&#039;.  &lt;br /&gt;
 SimpleBridge executeAckTimeoutMS: &#039;&#039;millis&#039;&#039;.&lt;br /&gt;
or in JavaScript syntax:&lt;br /&gt;
 SimpleBridge.connectTimeout(&#039;&#039;seconds&#039;&#039;);     &lt;br /&gt;
 SimpleBridge.defineAckTimeoutMS(&#039;&#039;millis&#039;&#039;);  &lt;br /&gt;
 SimpleBridge.executeAckTimeoutMS(&#039;&#039;millis&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
We are sorry for the inconsistent argument (seconds vs. milliseconds); these result from history and later added features. We will provide a consistent interface in later versions.&lt;br /&gt;
 &lt;br /&gt;
To set the default for individual language bridges:&lt;br /&gt;
 PythonBridge connectTimeout: &#039;&#039;seconds&#039;&#039;.      &lt;br /&gt;
 PythonBridge defineAckTimeoutMS: &#039;&#039;millis&#039;&#039;.  &lt;br /&gt;
 PythonBridge executeAckTimeoutMS: &#039;&#039;millis&#039;&#039;. &lt;br /&gt;
 &lt;br /&gt;
 CBridge connectTimeout: &#039;&#039;seconds&#039;&#039;.      &lt;br /&gt;
 CBridge defineAckTimeoutMS: &#039;&#039;millis&#039;&#039;.  &lt;br /&gt;
 CBridge executeAckTimeoutMS: &#039;&#039;millis&#039;&#039;. &lt;br /&gt;
 &lt;br /&gt;
 NodeJSBridge connectTimeout: &#039;&#039;seconds&#039;&#039;.      &lt;br /&gt;
 NodeJSBridge defineAckTimeoutMS: &#039;&#039;millis&#039;&#039;.  &lt;br /&gt;
 NodeJSBridge executeAckTimeoutMS: &#039;&#039;millis&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
You can retrieve the default values via corresponding getter messages:&lt;br /&gt;
 &amp;lt;someBridgeClass&amp;gt; connectTimeout =&amp;gt; that bridge type&#039;s connectTimeout&lt;br /&gt;
 &amp;lt;someBridgeClass&amp;gt; defineAckTimeoutMS =&amp;gt; that bridge type&#039;s defineAckTimeout in milliseconds&lt;br /&gt;
 &amp;lt;someBridgeClass&amp;gt; executeAckTimeoutMS =&amp;gt; that bridge type&#039;s executeAckTimeout in milliseconds&lt;br /&gt;
&lt;br /&gt;
&amp;quot;connectTimeout&amp;quot; is relevant, when connecting to a remote machine;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;quot;defineAckTimeoutMS&amp;quot; is the time expecco will wait for a confirmation after an action&#039;s code has been transferred to the bridge;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;quot;executeAckTimeoutMS&amp;quot; is the time expecco waits for an acknowledge after sending an action-step&#039;s data (pin values). See note below. &lt;br /&gt;
&lt;br /&gt;
To be effective, these default values must be set before a bridge connection is setup.&lt;br /&gt;
You can either place these expressions into the &amp;quot;startup.rc&amp;quot; file (in the expecco installation folder), or into a test suite as an elementary (Smalltalk or JavaScript) action which is executed as post-load action or as a prepare action of a testplan.&lt;br /&gt;
&lt;br /&gt;
The above control the default values for new bridge connections. You can also change an existing connection&#039;s parameter by sending the same messages to a concrete bridge.&lt;br /&gt;
&lt;br /&gt;
Expecco 21.2: &lt;br /&gt;
:You may have to adjust the executeAckTimeout, if huge amounts of data are transfered.&lt;br /&gt;
:(we encountered this limit eg. when transferring a vector of 1 mio floats to the bridge)&lt;br /&gt;
Expecco 22.1:&lt;br /&gt;
:Expecco adjusts this automatically to match the amount of data.&lt;br /&gt;
&lt;br /&gt;
== I don&#039;t see the difference between DLL actions and bridged C-actions; when to use which? ==&lt;br /&gt;
&lt;br /&gt;
DLL action blocks - when executed - will ensure that the specified DLL (shared object) is loaded into the running expecco program and directly called from within expecco. In other words: it executes in the same address space as expecco.&lt;br /&gt;
&lt;br /&gt;
On the other hand, C-Bridge actions are executed by a separate program (the &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;) and expecco communicates with that program via a socket connection.&lt;br /&gt;
&lt;br /&gt;
Both mechanisms have advantages and disadvantages:&lt;br /&gt;
&lt;br /&gt;
DLL actions:&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; very fast call (no remote procedure call)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; very fast data transmission (especially, big vectors can be passed quickly)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; can be used if only the binary is present and no compiler toolchain is needed/wanted&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; the called code may crash the expecco executable if it misbehaves or is provided with wrong arguments&amp;lt;BR&amp;gt;(notice: although expecco tries to catch any illegal memory references, it may still happen, that a called DLL-function misbehaves and overwrites/manipulates memory which it is not supposed to. For example, if it overwrites any data of expecco, there may be a later crash in expecco.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; the called code may block expecco or slow down the user interface&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; the called code may exit/terminate the current thread or the program and thus terminate expecco (i.e. make sure, it does not call &amp;quot;&amp;lt;code&amp;gt;exit()&amp;lt;/code&amp;gt;&amp;quot;). Although expecco sets the &amp;quot;atexit&amp;quot; handler, shared libraries may still find other means to terminate.&lt;br /&gt;
&lt;br /&gt;
Bridged Calls:&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; code runs completely isolated from expecco - the bridge may crash due to bad data or a bad library call, but expecco will remain alive. You&#039;ll get a fail-status of the corresponding action in expecco.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; additional data conversions or checks are easily added (in case the called function&#039;s interface requires complicated object structures, such as complex structures/unions, pointers to pointers, pointers to return values etc.)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; better support for debugging (writing log-entries, adding printfs or running the cBridge under a debugger)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; the expecco UI will not be blocked by a runaway bridged action&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; the bridged action can be executed on the local or on a remote machine&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; the bridged action can be executed on a different operating system or CPU architecture (eg. expecco runs on a Linux machine, the bridge on Windows or even in a RasperryPI)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; multiple bridged C actions can execute in parallel on multiple machines or in multiple processes on one machine&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; the round trip times are quite long compared to direct DLL calls (in the order of milliseconds, in contrast to direct DLL calls, which run in the order of nanoseconds)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; multiple round trips if many fields of returned object references have to be accessed&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; a C-compiler toolchain is needed (on the local or the target system, where the bridged C code is to be executed)&lt;br /&gt;
  &lt;br /&gt;
Despite the above mentioned performance differences, we highly recommend to use bridged C actions instead of direct DLL calls, iff the performance/round trip times are acceptable. The added safety due to the process boundaries makes it much easier to develop and maintain those.&lt;br /&gt;
&lt;br /&gt;
== How can I debug the code in the bridge ==&lt;br /&gt;
Expecco does include some limited debugging support for bridged code, but the level of support is different between individual bridges:&lt;br /&gt;
* Python, Node, Smalltalk, Groovy&amp;lt;br&amp;gt;Support breakpoints and single stepping. Walkback and some access to remote objects.&lt;br /&gt;
* C&amp;lt;br&amp;gt;Walkback and some access to remote objects. &lt;br /&gt;
&lt;br /&gt;
To debug bridged C-code, we recommend executing the bridge inside a debugger; for example, under Unix, you would compile your framework with the &amp;quot;-g&amp;quot; (debug) option, then open a shell terminal window and start the bridge under a debugger (say &amp;quot;lldb&amp;quot; or &amp;quot;gdb&amp;quot;) with:&lt;br /&gt;
 lldb cBridge&lt;br /&gt;
 &amp;gt;&amp;gt; r --server --port 8899&lt;br /&gt;
then change the expecco settings for the CBridge to &amp;quot;&#039;&#039;Connect to an already running bridge&#039;&#039;&amp;quot; and also define the port  there. Expecco will then connect to your debugged bridge instead of starting one itself.&lt;br /&gt;
A similar setup is to be used when debugging with Eclipse or Visual Studio on Windows. &lt;br /&gt;
&lt;br /&gt;
To debug Python code, you can check the &amp;quot;&#039;&#039;Disable Debugger&#039;&#039;&amp;quot; flag in the Python settings, and attach a Python debugger (eg. VSCode) to the running Python process.&lt;br /&gt;
&lt;br /&gt;
== Security Considerations ==&lt;br /&gt;
Make sure that remote bridges are only reachable from inside your local network and only from trusted hosts. You should configure your firewall as appropriate, or run tests in an isolated network. You may also configure switches and routers to limit access, or use a secondary interface (alternative lan or wifi).&lt;br /&gt;
&lt;br /&gt;
Another recommened option is to setup an ssh tunnel for the particular port(s) in question.&lt;br /&gt;
&lt;br /&gt;
All bridges support command line arguments to only accept connections from a particular host; this option should be used if a remote bridge is started via a remote shell command.&lt;br /&gt;
&lt;br /&gt;
=== SSL/TLS Encrypted Connections ===&lt;br /&gt;
All bridges support SSL/TLS encrypted connections. This provides both confidentiality and (with mutual TLS) authentication.&lt;br /&gt;
&lt;br /&gt;
To enable SSL for a bridge connection, configure the following in the expecco bridge settings (under &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Python&#039;&#039;&amp;quot;):&lt;br /&gt;
* &#039;&#039;&#039;Use SSL&#039;&#039;&#039;: enable TLS encryption&lt;br /&gt;
* &#039;&#039;&#039;Certificate File&#039;&#039;&#039;: PEM file containing the server certificate and private key (used by the bridge process)&lt;br /&gt;
* &#039;&#039;&#039;Client Certificate&#039;&#039;&#039;: the client certificate for mutual TLS authentication. The PEM content is stored directly in the expecco preferences. Use the &#039;&#039;&#039;&amp;quot;...&amp;quot;&#039;&#039;&#039; button to load from a file, &#039;&#039;&#039;&amp;quot;?&amp;quot;&#039;&#039;&#039; to inspect the certificate chain, and &#039;&#039;&#039;&amp;quot;X&amp;quot;&#039;&#039;&#039; to clear it. On load, the certificate chain is validated (expiry, CA flag, key identifier match).&lt;br /&gt;
&lt;br /&gt;
When the client certificate PEM includes the CA certificate in the chain, the CA is automatically trusted for server verification.&lt;br /&gt;
&lt;br /&gt;
Certificate generation is built into the cBridge and Python bridge executables using Ed25519 keys:&lt;br /&gt;
 cBridge --generateCA ca.pem --cn &amp;quot;My CA&amp;quot;&lt;br /&gt;
 cBridge --generateCert server.pem --ca ca.pem --cn myhost&lt;br /&gt;
 cBridge --generateCert client.pem --ca ca.pem --cn expecco&lt;br /&gt;
&lt;br /&gt;
Generated PEM files include the full certificate chain.&lt;br /&gt;
&lt;br /&gt;
For mutual TLS (mTLS), start the remote bridge with the &amp;lt;code&amp;gt;--clientAuth&amp;lt;/code&amp;gt; flag:&lt;br /&gt;
 cBridge --port 8855 --ssl --cert server.pem --clientAuth&lt;br /&gt;
&lt;br /&gt;
See [[Cbridge_setup#SSL/TLS_Connection_to_a_Remote_CBridge|CBridge Setup: SSL/TLS Connection]] for detailed instructions.&lt;br /&gt;
&lt;br /&gt;
== File Transfer and Remote Directory Operations ==&lt;br /&gt;
All bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk) support transferring files between expecco and the remote bridge:&lt;br /&gt;
* &amp;lt;code&amp;gt;putFile: localPath to: remotePath&amp;lt;/code&amp;gt; — upload a file to the bridge&lt;br /&gt;
* &amp;lt;code&amp;gt;getFile: remotePath to: localPath&amp;lt;/code&amp;gt; — download a file from the bridge&lt;br /&gt;
* &amp;lt;code&amp;gt;makeDirectory: remotePath&amp;lt;/code&amp;gt; — create a directory (including parent directories) on the bridge&lt;br /&gt;
&lt;br /&gt;
These operations use the existing bridge connection and work over SSL if enabled. They are useful for deploying test data, collecting results, or transferring compiled binaries.&lt;br /&gt;
&lt;br /&gt;
== [OS X Only] CrashReporter Dialog Boxes ==&lt;br /&gt;
You may get annoying dialog boxes telling about &amp;quot;&#039;&#039;Unexpected Termination&#039;&#039;&amp;quot; whenever a bridge is hard terminated via the &amp;quot;&#039;&#039;Terminate&#039;&#039;&amp;quot; button in the debugger.&lt;br /&gt;
&lt;br /&gt;
This is a &amp;quot;&#039;&#039;feature&#039;&#039;&amp;quot; of the OS X system, not controlled by expecco.&lt;br /&gt;
&lt;br /&gt;
You can disable this by executing the following command in a console terminal:&lt;br /&gt;
 defaults write com.apple.CrashReporter DialogType none&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Back to [[FAQ/en | FAQ]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Cbridge_setup&amp;diff=31330</id>
		<title>Cbridge setup</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Cbridge_setup&amp;diff=31330"/>
		<updated>2026-05-27T13:48:21Z</updated>

		<summary type="html">&lt;p&gt;Sv: update SSL settings: client cert stored in prefs, load/inspect/clear buttons, chain validation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= CBridge Setup =&lt;br /&gt;
&lt;br /&gt;
In order to compile and execute C/C++ actions, a C compiler toolchain has to be installed on the machine, where the Bridge executable (Windows: &amp;lt;code&amp;gt;cBridge.exe&amp;lt;/code&amp;gt; / Unix: &amp;lt;code&amp;gt;cBridge&amp;lt;/code&amp;gt;) runs.&lt;br /&gt;
&amp;lt;br&amp;gt;Typically this is the local machine on which expecco runs, but it may be any other machine in your reachable network.&lt;br /&gt;
&amp;lt;br&amp;gt;The CPU architecture and or operating system may be (and often is) different from the CPU which executes expecco, therefore the C-code is compiled on the target machine (i.e. not cross-compiled).&lt;br /&gt;
&lt;br /&gt;
== C-Compiler Toolchain Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Windows + Borland Compiler (32bit) ===&lt;br /&gt;
The compiler is a bit outdated, but still free and useful.&amp;lt;br&amp;gt;However, it only supports 32bit programs. Thus, it cannot be used if you need access to 64bit dlls.&amp;lt;br&amp;gt;(on the other hand, if you need to interact with a 32bit dll to communicate with some hardware device, you&#039;ll must use a 32bit cBridge).&lt;br /&gt;
&lt;br /&gt;
We recommend to install the toolchain at its default installation path (typically &amp;quot;&amp;lt;code&amp;gt;C:\borland&amp;lt;/code&amp;gt;&amp;quot;). Then, the provided cc-compile script for borland can be used unchanged.&lt;br /&gt;
&lt;br /&gt;
=== Windows + MINGW Compiler (32 or 64bit) ===&lt;br /&gt;
The mingw toolchain is based on the gcc compiler. This is recommended and preferred over borland.&lt;br /&gt;
&lt;br /&gt;
=== Windows + Microsoft Visual C / Visual Studio === &lt;br /&gt;
There is no need to install the full Visual Studio IDE. Only the C-compiler, linker and libraries are required. &lt;br /&gt;
Thus, you can untoggle all additional optional packages during the installation.&lt;br /&gt;
&lt;br /&gt;
Check for the &amp;quot;&amp;lt;code&amp;gt;cl&amp;lt;/code&amp;gt;&amp;quot; command (being in your &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt;) or find and remember the path to it (typically somewhere under &amp;quot;&amp;lt;code&amp;gt;c:\Program Files\Microsoft\...&amp;lt;/code&amp;gt;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
=== Unix / Linux ===&lt;br /&gt;
Install whatever packages are required; check if the &amp;quot;&amp;lt;code&amp;gt;cc&amp;lt;/code&amp;gt;&amp;quot; command is found along your &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; (before starting expecco),&lt;br /&gt;
or alternatively, remember the path to the &amp;quot;&amp;lt;code&amp;gt;cc&amp;lt;/code&amp;gt;&amp;quot; command.&lt;br /&gt;
 &lt;br /&gt;
Regardless of which compiler you use, &lt;br /&gt;
please remember the installation path. You will need it later unless the compiler is found along your &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Check if it Already Works ==&lt;br /&gt;
We provide a number of setups for common installations.&lt;br /&gt;
In many situations, this will already be correct for your setup.&lt;br /&gt;
&lt;br /&gt;
To check, create a new elementary-bridgedC action, and run it.&lt;br /&gt;
(the initial tree which is created with examples also contains a simple C action).&lt;br /&gt;
&lt;br /&gt;
If you get a green OK result, you&#039;re already done.&lt;br /&gt;
If not, your setup needs to be adjusted.&lt;br /&gt;
&lt;br /&gt;
Read the chapter at the end of this page on step-by-step setup verification.&lt;br /&gt;
&lt;br /&gt;
== The Compile Script ==&lt;br /&gt;
For compilation, the cBridge program calls a batch/shell script, which is responsible for compilation of the C-code to a DLL/shared object file.&lt;br /&gt;
This script may need to be edited.&lt;br /&gt;
We recommend, that you navigate to the folder where the cBridge executable is located, take one of the existing scripts as template, make a copy under a new name, and then edit this copy to suit your needs.&lt;br /&gt;
&lt;br /&gt;
Take one of the existing scripts which uses the same compiler (borland/mingw/visualC).&lt;br /&gt;
&lt;br /&gt;
In the editor, check the &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; setting, and edit it as appropriate, finally save it.&lt;br /&gt;
&lt;br /&gt;
Back in expecco, go to the cBridge settings under the external-script settings,&lt;br /&gt;
and change the CC-script setting there (&amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Shutdown any already running bridge (&amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Debugging&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Shutdown all Bridge Connections&#039;&#039;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Go back to the C-action and repeat the quick check.&lt;br /&gt;
&lt;br /&gt;
Eventually, you should see a green OK result.&lt;br /&gt;
&lt;br /&gt;
== Special Additional Libraries ==&lt;br /&gt;
&lt;br /&gt;
It may be required that your C-code needs additional shared libraries to be linked against your code.&lt;br /&gt;
The easiest is to add those libraries and corresponding command line options to the CC-script&#039;s compiler call command.&lt;br /&gt;
The details depend on the compiler used.&lt;br /&gt;
You may need to do a &amp;quot;&amp;lt;code&amp;gt;cc --help&amp;lt;/code&amp;gt;&amp;quot;, &amp;quot;&amp;lt;code&amp;gt;cl/help&amp;lt;/code&amp;gt;&amp;quot; or similar, to figure out which command line options are required.&lt;br /&gt;
&lt;br /&gt;
= Remote C-Bridges =&lt;br /&gt;
You can run any number of cBridges on any machine within your network (and also multiple cBridges on your local or a remote machine), and execute C-actions there. For this, the following setup steps are to be performed:&lt;br /&gt;
&lt;br /&gt;
* copy the cbridge executable and its support files to a new folder on the target machine; the files are found below the expecco installation folder&amp;lt;br&amp;gt;(eg. &amp;quot;&amp;lt;code&amp;gt;c:\Program Files\exept\expecco&amp;lt;/code&amp;gt;&amp;quot;) in &amp;quot;&amp;lt;code&amp;gt;packages\bridgeFramework\cBridge\cLibrary&amp;lt;/code&amp;gt;&amp;quot;.&lt;br /&gt;
:The easiest way is to copy the whole folder. Make sure that the copied folder matches the target machine&#039;s architecture (i.e. if the target is a Linux machine, you must obviously copy the files from a Linux installation, and same so for Windows machines).&lt;br /&gt;
&lt;br /&gt;
* on the remote machine, make sure that the cBridge is running; either by executing a remote command from inside your expecco suite, or by adding the cBridge startup to a cron tab (Unix/Linux) or the service list or autoexec.bat (Windows).&lt;br /&gt;
:As a test, start it manually with: &amp;quot;&amp;lt;code&amp;gt;cBridge --port 8856&amp;lt;/code&amp;gt;&amp;quot;, and connect to it from expecco (change the settings (&amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;) to connect to an already running cBridge at that port).&lt;br /&gt;
&lt;br /&gt;
* if in doubt, start the cBridge with a &amp;quot;&amp;lt;code&amp;gt;--help&amp;lt;/code&amp;gt;&amp;quot; option.&lt;br /&gt;
&lt;br /&gt;
=== CBridge Command Line Arguments ===&lt;br /&gt;
&lt;br /&gt;
* --help&amp;lt;br&amp;gt;Prints a list of the supported comamnd line arguments&lt;br /&gt;
* --localOnly&amp;lt;br&amp;gt;only accept connections from the local machine&lt;br /&gt;
* --host &#039;&#039;hostname&#039;&#039;&amp;lt;br&amp;gt;connect to that host instead of waiting for incoming connections&lt;br /&gt;
* --port&amp;lt;br&amp;gt;the TCP port on which the bridge is waiting for incoming requests or connecting to (with --host argument)&lt;br /&gt;
* -- keepAlive&amp;lt;br&amp;gt;after the first connection, keep on waiting for more incoming connections. Without this, the bridge will only handle a single session and exit after that.&lt;br /&gt;
* --log&amp;lt;br&amp;gt;log actions on stderr&lt;br /&gt;
* --log2&amp;lt;br&amp;gt;even more detailed log&lt;br /&gt;
* --ccScript &#039;&#039;scriptFile&#039;&#039;&amp;lt;br&amp;gt;Use the given script file (a shell or batch script) to compile&lt;br /&gt;
* --includes &#039;&#039;files&#039;&#039;&amp;lt;br&amp;gt;Additional include folders passed to the compile script&lt;br /&gt;
* --dlls &#039;&#039;files&#039;&#039;&amp;lt;br&amp;gt;Additional dlls (shared libraries) to be linked against actions&lt;br /&gt;
* --testCompile&amp;lt;br&amp;gt;For a standalone selftest if compilation  works. Compiles a dummy almost empty source file&lt;br /&gt;
&lt;br /&gt;
More arguments may be recognized, depending on the cBridge version. Use &amp;quot;--help&amp;quot; to see more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== SSL/TLS Connection to a Remote CBridge ===&lt;br /&gt;
&lt;br /&gt;
The cBridge supports encrypted TLS connections with optional mutual certificate authentication (mTLS).&lt;br /&gt;
&lt;br /&gt;
==== Generating Certificates ====&lt;br /&gt;
The cBridge can generate Ed25519 CA and server/client certificates directly:&lt;br /&gt;
&lt;br /&gt;
 cBridge --generateCA ~/.ssl/ca.pem --cn &amp;quot;My CA&amp;quot; --days 3650&lt;br /&gt;
 cBridge --generateCert ~/.ssl/server.pem --ca ~/.ssl/ca.pem --cn myhost&lt;br /&gt;
 cBridge --generateCert ~/.ssl/client.pem --ca ~/.ssl/ca.pem --cn expecco&lt;br /&gt;
&lt;br /&gt;
Each generated PEM file contains the certificate, private key, and the CA certificate chain. The &amp;lt;code&amp;gt;--cn&amp;lt;/code&amp;gt; option sets the common name (default: localhost), &amp;lt;code&amp;gt;--days&amp;lt;/code&amp;gt; sets the validity period (default: 3650).&lt;br /&gt;
&lt;br /&gt;
The same certificate generation is also available via the Python bridge script (&amp;lt;code&amp;gt;--generateCA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;--generateCert&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Starting the CBridge with SSL ====&lt;br /&gt;
&lt;br /&gt;
 cBridge --port 8855 --ssl --cert ~/.ssl/server.pem&lt;br /&gt;
&lt;br /&gt;
A combined PEM file (certificate + key in one file) is used by default. Separate files are also supported:&lt;br /&gt;
&lt;br /&gt;
 cBridge --port 8855 --ssl --cert server.crt --key server.key&lt;br /&gt;
&lt;br /&gt;
==== Mutual TLS (Client Certificate Authentication) ====&lt;br /&gt;
&lt;br /&gt;
To require clients to present a certificate signed by the same CA:&lt;br /&gt;
&lt;br /&gt;
 cBridge --port 8855 --ssl --cert ~/.ssl/server.pem --ca ~/.ssl/ca.pem --clientAuth&lt;br /&gt;
&lt;br /&gt;
Clients must then be configured with a client certificate (see the expecco CBridge settings dialog).&lt;br /&gt;
&lt;br /&gt;
==== Expecco Settings for SSL ====&lt;br /&gt;
&lt;br /&gt;
In expecco, configure the CBridge connection under &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;:&lt;br /&gt;
* &#039;&#039;&#039;Use SSL&#039;&#039;&#039;: enable encrypted connection&lt;br /&gt;
* &#039;&#039;&#039;Certificate File&#039;&#039;&#039;: the server certificate PEM (used by the bridge process)&lt;br /&gt;
* &#039;&#039;&#039;Client Certificate&#039;&#039;&#039;: load a client certificate PEM for mutual TLS authentication. The certificate is stored in the expecco preferences (not as a file path). Use the buttons:&lt;br /&gt;
** &#039;&#039;&#039;&amp;quot;...&amp;quot;&#039;&#039;&#039; to load a certificate from a PEM file&lt;br /&gt;
** &#039;&#039;&#039;&amp;quot;?&amp;quot;&#039;&#039;&#039; to inspect the certificate chain (shows subject, issuer, validity, algorithm, CA flag, private key presence, and chain verification via AuthorityKeyIdentifier)&lt;br /&gt;
** &#039;&#039;&#039;&amp;quot;X&amp;quot;&#039;&#039;&#039; to remove the stored certificate&lt;br /&gt;
: On load, the certificate chain is validated: the leaf certificate must not be expired, the CA must have the BasicConstraints CA flag set, and the AuthorityKeyIdentifier must match the CA&#039;s SubjectKeyIdentifier (or the issuer DN must match).&lt;br /&gt;
&lt;br /&gt;
When the client certificate PEM includes the CA certificate in the chain, the CA is automatically trusted for server certificate verification — no need to enable &amp;quot;Allow Self-Signed Certificates&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The same SSL and client certificate settings are also available in the Python bridge settings dialog (&amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Python&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
==== File Transfer and Directory Operations ====&lt;br /&gt;
All bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk) support file transfer to and from the remote bridge:&lt;br /&gt;
* &amp;lt;code&amp;gt;putFile: localPath to: remotePath&amp;lt;/code&amp;gt; — upload a file&lt;br /&gt;
* &amp;lt;code&amp;gt;getFile: remotePath to: localPath&amp;lt;/code&amp;gt; — download a file&lt;br /&gt;
* &amp;lt;code&amp;gt;makeDirectory: remotePath&amp;lt;/code&amp;gt; — create a directory (including parent directories)&lt;br /&gt;
&lt;br /&gt;
These operations work over the bridge&#039;s existing connection (including SSL if enabled).&lt;br /&gt;
&lt;br /&gt;
= Step-by-Step Problem Finding/Fixing =&lt;br /&gt;
&lt;br /&gt;
=== Ensure that the cBridge executable is present and can be executed ===&lt;br /&gt;
* goto the expecco installation folder (typically somewhere under &amp;quot;&amp;lt;code&amp;gt;c:\Program Files\exept\expecco\&amp;lt;/code&amp;gt;&amp;quot;), and look for files named &amp;quot;&amp;lt;code&amp;gt;cBridge.exe&amp;lt;/code&amp;gt;&amp;quot; or &amp;quot;&amp;lt;code&amp;gt;cBridge32.exe&amp;lt;/code&amp;gt;&amp;quot; or &amp;quot;&amp;lt;code&amp;gt;cBridge&amp;lt;/code&amp;gt;&amp;quot; (under Unix/Linux). It is typically found in a sub folder named &amp;quot;&amp;lt;code&amp;gt;packages/expecco/bridgeFramework/cBridge&amp;lt;/code&amp;gt;&amp;quot;.&lt;br /&gt;
* open a shell- or cmd window (and navigate there).&lt;br /&gt;
* type &amp;quot;&amp;lt;code&amp;gt;cBridge --help&amp;lt;/code&amp;gt;&amp;quot; (with powershell: &amp;quot;&amp;lt;code&amp;gt;.\cBridge --help&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
:: if that fails (does not output some useful help text), make sure that it can be executed.&amp;lt;br&amp;gt;Maybe your security policy is too strict ot the installation is incomplete.&lt;br /&gt;
* start the bridge with &amp;quot;&amp;lt;code&amp;gt;cBridge --log&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
:: it should output some messages, the last being &amp;quot;&amp;lt;code&amp;gt;... listening on port xxxx&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
* if the cBridge is to run on a machine different from the one expecco is running on, make sure that the firewall allows for connections between the two machines (at the desired port nr)&lt;br /&gt;
* if required, use another port (i.e. run it with &amp;quot;&amp;lt;code&amp;gt;cBridge --log --port &amp;lt;Nr&amp;gt;&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
:: now we have a cBridge running, ready to accept connections from expecco at the given port nr.&lt;br /&gt;
* keep the shell/cmd window open; we will need it later (and also to see any diagnostic output)&lt;br /&gt;
&lt;br /&gt;
=== Ensure that the cBridge is reachable from expecco ===&lt;br /&gt;
for this, we first try to connect to that already running bridge (instead of letting expecco start it itself)&lt;br /&gt;
* in expecco, open the settings and navigate to the cBridge settings: &lt;br /&gt;
:: &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;&lt;br /&gt;
* check the &amp;quot;&#039;&#039;Connect to already Running Bridge&#039;&#039;&amp;quot; box.&lt;br /&gt;
:: enter CBridge Host and Port as &amp;quot;&amp;lt;code&amp;gt;localhost&amp;lt;/code&amp;gt;&amp;quot; and the above port number (default is 8855)&lt;br /&gt;
* close the settings dialog (without saving the settings for now, when asked)&lt;br /&gt;
* open a new project.&amp;lt;br&amp;gt;The default project will contain a sample &amp;quot;Hello World&amp;quot; C-action, which can be used for the smoke test.&lt;br /&gt;
* in the expecco tree, find the &amp;quot;&amp;lt;code&amp;gt;Simple Elementary Action (C)&amp;lt;/code&amp;gt;&amp;quot; (under the &amp;quot;Activities&amp;quot; group).&lt;br /&gt;
* run it&lt;br /&gt;
:: if the error states that no connection could be setup, check your security policy, firewall etc. and repeat&lt;br /&gt;
:: if the error states that the compilation failed, the bridge connection works, but the compilation script setup is wrong. Proceed.&lt;br /&gt;
&lt;br /&gt;
=== Ensure that the compilation works ===&lt;br /&gt;
the cBridge needs a C-compiler for its operation; to verify,&lt;br /&gt;
* stop the manually started C-bridge (in the shell/cmd window) by pressing CTRL-C there&lt;br /&gt;
* depending on the C-compiler you intend to use, one of the &amp;quot;compile_xxx.bat&amp;quot; or &amp;quot;compile_xxx.sh&amp;quot; script files will be used. The task to be performed by these scripts is to compile a given C-file.&lt;br /&gt;
* check which compiler you installed and intent to use (MSVC, Mingw, gcc, clang or bcc), and look for a corresponding script file.&lt;br /&gt;
* check if the compiler is correctly installed (especially MSVC and MINGW sometimes make trouble here).&lt;br /&gt;
:: one particular problem with MSVC is when deinstalling and reinstalling another version. There seem to be leftover files and/or registry entries which may break the installation (this happend to one of our customers, and also to us when upgrading)&lt;br /&gt;
* Enter the compile-command (&amp;quot;cl&amp;quot;, &amp;quot;cc&amp;quot;, &amp;quot;gcc&amp;quot; or &amp;quot;clang&amp;quot;) on a command line (cmd or shell)&lt;br /&gt;
:: check that you get an answer&lt;br /&gt;
:: try to compile a one-liner (eg. &amp;quot;&amp;lt;code&amp;gt;main() { printf(&amp;quot;hello\n&amp;quot;); }&amp;lt;/code&amp;gt;&amp;quot; and run it to see if it links correctly. Run it!&lt;br /&gt;
* check if the bridge&#039;s cc script file works by running &amp;quot;&amp;lt;code&amp;gt;cBridge --log --ccScript &amp;lt;scriptfilename&amp;gt; --testCompile&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
:: if required, make a copy of one of the script files (the one you think is best to start with) and fix any path inside. If required, add echo statements to show what is going on. Keep the original script and create a new one.&lt;br /&gt;
:: under Windows: in the script, the PATH to the compiler is typically searched and set; for example by calling the vcvarsall.bat script which is provided by microsoft. If required, change the line which calls this (you can also add this batch-call to your autoexec.bat and remove the line from the script). In any case: at the end, the &amp;quot;cl&amp;quot; command should be found along your path. &lt;br /&gt;
* the --testCompile will generate a piece of code which outputs &amp;quot;here is foo&amp;quot;; i.e. on your system (we use mingw), the command is &amp;quot;&amp;lt;code&amp;gt;cBridge --log --ccScript compile_windows_mingw.bat&amp;quot; --testCompile&amp;lt;/code&amp;gt;&amp;quot;, and the output is &amp;quot;here is foo&amp;quot; - &amp;quot;void pointer size: 8&amp;quot;, followed by the usual &amp;quot;listening on port&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
=== Change the Settings in expecco ===&lt;br /&gt;
* open the cBridge settings again&lt;br /&gt;
* uncheck the &amp;quot;&#039;&#039;Connect to already running bridge&#039;&#039;&amp;quot; box&lt;br /&gt;
* enter the name of the compile script into the &amp;quot;CC-script&amp;quot; field (possibly the name of the new script)&lt;br /&gt;
* shutdown any already running bridge&lt;br /&gt;
* try executing the expecco-C action again&lt;br /&gt;
* if you get a green outcome, save your expecco settings.&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=FAQ_on_Bridges/en&amp;diff=31329</id>
		<title>FAQ on Bridges/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=FAQ_on_Bridges/en&amp;diff=31329"/>
		<updated>2026-05-27T07:02:32Z</updated>

		<summary type="html">&lt;p&gt;Sv: add SSL/TLS section and file transfer/makeDirectory documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Why Bridged Actions and not Script Actions? ==&lt;br /&gt;
&lt;br /&gt;
Script actions will start the language interpreter anew for every such action. Thus, no internal state can be held and transferred from one such action to another. Especially, it is not possible to open a communication channel on one script action, pass it back to expecco, and use it with different followup script actions (i.e. actions like &amp;quot;&#039;&#039;open-port&#039;&#039;&amp;quot; / &amp;quot;&#039;&#039;send message&#039;&#039;&amp;quot; / &amp;quot;&#039;&#039;receive message&#039;&#039;&amp;quot; / &amp;quot;&#039;&#039;close port&#039;&#039;&amp;quot; etc.).&lt;br /&gt;
&lt;br /&gt;
For this, it is required to call individual API-entries inside the bridge code, and return handles from the bridge to expecco, which can later be passed to other API entries.&amp;lt;br&amp;gt;This of course only makes sense, if the interpreter stays active during the lifetime of the connection.&lt;br /&gt;
&lt;br /&gt;
On the other hand, script actions are easier to use if a self contained program or app is to be started, or which performs a single processing action or which stays alive for longer, serving a socket or database. In any such case, there is no need to exchange individual data objects (such as handles) with expecco. It may however interact with expecco through other communication channels, such as sockets, RPC calls, SOAP interface or stdin/stdout text ports.&lt;br /&gt;
&lt;br /&gt;
Thus, you will typically use script actions to start server applications and bridged actions to call individual functions of a framework.&lt;br /&gt;
&lt;br /&gt;
== Which Languages are Supported ==&lt;br /&gt;
&lt;br /&gt;
By the time this chapter was written, bridged code execution is supported for:&lt;br /&gt;
* Java (using either Groovy or Jython as &amp;quot;&#039;&#039;glue&#039;&#039;&amp;quot; or directly using proxy objects in expecco)&lt;br /&gt;
* Python (both Python 2.7 and Python 3.x)&lt;br /&gt;
* .NET (using IronPython as &amp;quot;&#039;&#039;glue&#039;&#039;&amp;quot; or directly via proxy objects)&lt;br /&gt;
* NodeJS (i.e. JavaScript)&lt;br /&gt;
* C/C++ (Root/Cling is being developed currently)&lt;br /&gt;
* Smalltalk (Smalltalk/X and VisualWorks are currently supported; VisualAge may come in the near future, if there is sufficient customer interest)&lt;br /&gt;
* Ruby&lt;br /&gt;
Plans are to support Dart and Scheme in the future.&lt;br /&gt;
&lt;br /&gt;
== How are Bridges Started ==&lt;br /&gt;
&lt;br /&gt;
Bridges on the local machine are usually automatically started by expecco itself, when the first bridged action is executed (and stays alive, until expecco is terminated, or bridge connections are closed via the menu or via an expecco action block). Some language interpreters may take a few seconds to come up, so the first such action will execute relatively slow compared to later actions. You can add a dummy (empty) bridged action to your startup actions (project&#039;s postLoad action) to prepare the bridged interpreter and have it startup in parallel. &lt;br /&gt;
&lt;br /&gt;
Bridges on other machines, or additional bridges on the local machine must be started by executing a bridge start action block or simply by executing a shell/batch action to call the corresponding language interpreter (python, node, etc.). On Windows, a powershell action can be used for remote execution (given that your Windows security settings allow that). On Unix, a shell action executin a remote shell / ssh command could be used.&lt;br /&gt;
&lt;br /&gt;
== Who Initiates the Connection ==&lt;br /&gt;
&lt;br /&gt;
Normally, expecco opens a port and tells the bridge (via command line argument) to which port to connect. Depending on the setup of your network and firewall, it may sometimes be required to reverse this, and let the bridge open a port and expecco connect to it. &lt;br /&gt;
&lt;br /&gt;
For this, some bridges support command line arguments (&amp;quot;--server&amp;quot; and &amp;quot;--port&amp;quot;) to specify this behavior. Details are found in the individual bridge documentation pages.&lt;br /&gt;
&lt;br /&gt;
== Ports Used for Bridge Communication ==&lt;br /&gt;
&lt;br /&gt;
Unless ports are configured in the expecco settings,&lt;br /&gt;
the following default ports are used (bridges typically listen on or connect to this port, unless an explicit &amp;quot;--port&amp;quot; argument is given):&lt;br /&gt;
&lt;br /&gt;
 Python      8677 , 8678 (debug) &lt;br /&gt;
   Python2     8679 , 8680 (debug)&lt;br /&gt;
   Python3     8681 , 8682 (debug)&lt;br /&gt;
 Jython      8777 , 8778 (debug)&lt;br /&gt;
 IronPython  8787 , 8788 (debug)&lt;br /&gt;
 Node        8577 , 8578 (debug)&lt;br /&gt;
 Electron    8588 , 8589 (debug)&lt;br /&gt;
 [[Embedded_Systems_C_Bridge_API |CBridge]]     8855 (also for Root/Cling)&lt;br /&gt;
 Smalltalk   8877&lt;br /&gt;
 VASmalltalk 8879&lt;br /&gt;
 VWSmalltalk 8881&lt;br /&gt;
 Dart        8885&lt;br /&gt;
 Ruby        8977&lt;br /&gt;
 Scheme      8599&lt;br /&gt;
&lt;br /&gt;
Note: for some bridges, two connections are used, the debug port being used by the debugger to inspect data and to support breakpoints, single stepping etc. &lt;br /&gt;
&amp;lt;br&amp;gt;Note: expecco will try successive alternative ports, if the default port happens to be already in use.&lt;br /&gt;
&lt;br /&gt;
Debugging is not supported on all bridges (eg. the C-bridge does not).&lt;br /&gt;
&lt;br /&gt;
== What are Proxy Objects ==&lt;br /&gt;
These are placeholder objects inside expecco, which will look like regular Smalltalk (or JavaScript) objects inside expecco, but will forward any call via the socket ower to the bridge partner. &lt;br /&gt;
&lt;br /&gt;
Thus, they can be used transparently inside Smalltalk and JavaScript elementary actions, performing whatever is implemented in the remote side.&lt;br /&gt;
&lt;br /&gt;
For example, given a Java bridge connection named &amp;quot;bridge&amp;quot;, you can instantiate a remote object there from within your local JavaScript code with:&lt;br /&gt;
 var remoteArrayListClass, myList;&lt;br /&gt;
 remoteArrayListClass = bridge.resolveType(&amp;quot;java.util.ArrayList&amp;quot;);&lt;br /&gt;
 myList = new remoteArrayListClass(10);&lt;br /&gt;
 myList.add(&amp;quot;hello&amp;quot;);&lt;br /&gt;
 ...&lt;br /&gt;
in a Smalltalk action, the code is similar:&lt;br /&gt;
 |remoteArrayList myList|&lt;br /&gt;
 remoteArrayListClass := bridge resolveType:&#039;java.util.ArrayList&#039;.&lt;br /&gt;
 myList := remoteArrayListClass new:10.&lt;br /&gt;
 myList add:&#039;hello&#039;.&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
This works without any remote code injection and is typically a bit faster than via Groovy. However, the language syntax is the local expecco syntax, which might be inconvenient to hard-core Java programmers (and the same is true for proxies to other language&#039;s bridge objects).&lt;br /&gt;
&lt;br /&gt;
Remote proxy objects are also returned by the &amp;quot;&amp;lt;code&amp;gt;makeRef&amp;lt;/code&amp;gt;&amp;quot; API as described in the API documentation, and when remote objects are inspected in the expecco data inspector window.&lt;br /&gt;
&lt;br /&gt;
== What can I do if a Bridge is Dead(locked) ==&lt;br /&gt;
&lt;br /&gt;
The code executed in the bridge may run into an endless loop (for example, if your elementary code contains a bug), or when it calls a function which does not return.&lt;br /&gt;
As a consequence, the corresponding elementary action will not finish.&lt;br /&gt;
&lt;br /&gt;
Try to stop or abort the execution via the corresponding toolbar function (in the expecco editor page).&lt;br /&gt;
Even though the corresponding expecco action has now finished (i.e. expecco will no longer wait for the action&#039;s return value and status), a problem might be reported when expecco is about to call another action inside that bridge: the bridge will still be in its loop, and the bridge will therefore not respond and expecco will report that the bridge is no longer answering.&lt;br /&gt;
&lt;br /&gt;
You now have to kill the bridge, and start a new one, with the undesired consequence of loosing any state inside the previous bridge incarnation. Especially, any connections in the previous bridge are now lost.&lt;br /&gt;
&lt;br /&gt;
To kill the bridge, perform one of the following:&lt;br /&gt;
* click the &amp;quot;&#039;&#039;Terminate Bridge&#039;&#039;&amp;quot; toolbar button in the &amp;quot;Test/Demo&amp;quot; tab.&amp;lt;br&amp;gt;This will terminate that language&#039;s bridges&lt;br /&gt;
* select &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Debugging&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Close all Bridge Connections&#039;&#039;&amp;quot;&amp;lt;br&amp;gt;This will terminate all running bridges (maybe this is not what you want)&lt;br /&gt;
* select &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Debugging&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;OS Process Monitor&#039;&#039;&amp;quot; to get a list of all OS processes which have been started by expecco, select the one to terminate and choose &amp;quot;&#039;&#039;Terminate&#039;&#039;&amp;quot; from the context menu.&lt;br /&gt;
* select and terminate the bridge process in the Task Manager (Windows) or find its processID with the &amp;quot;ps&amp;quot; command and terminate it via the &amp;quot;kill&amp;quot; command (Unix)&lt;br /&gt;
&lt;br /&gt;
If the bridge was not originally started by expecco (eg. if it is a remote bridge, which was started automatically or by a remote command), you have to log into that remote machine and terminate the bridge there.&lt;br /&gt;
&lt;br /&gt;
In a production system, you may add time limits to actions which might suffer from locked bridges, and add a bridge-terminate action (found in the Standard Library) to be triggered via the exception pin of the time-controlled action.&lt;br /&gt;
&lt;br /&gt;
== I got an Object (Reference) from a Bridge but Access to its Fields is Slow ==&lt;br /&gt;
Be reminded ([[#What_are_Proxy_Objects |see above]]), that when an object (reference) is returned from a bridge to expecco, a proxy (placeholder object) is created inside expecco, which is what appears at the output pin.&lt;br /&gt;
This proxy object will intercept any calls to it and forward them to the real object inside the bridge, then wait for a response (the return value) and encode that again as a proxy.&lt;br /&gt;
&lt;br /&gt;
Thus, every such operation involves a round trip which is typically in the order of milliseconds (if the bridge is on a remote machine, and additional routers/switches are involved, the round trip times may even be in the 10-millisecond range).&lt;br /&gt;
These times can easily add up to seconds, for example if you enumerate a remote collection with many elements. &lt;br /&gt;
&lt;br /&gt;
Possible solutions to that problem:&lt;br /&gt;
* install the code which enumerates the object inside the bridge (i.e. define another elementary action or require/import a piece of code which contains this functionality. Then call this code which runs completely inside the bridge.&lt;br /&gt;
* pass the object&#039;s encoding (for example as JSON) and decode it on the expecco side for the enumeration. This one call will then probably run much slower, but further processing (enumeration of elements) is much faster. This is the way to go, if bulk data has been collected inside the bridge, which has to be analyzed inside expecco afterwards.&amp;lt;br&amp;gt;Be aware though, that the object inside expecco is effectively a &amp;quot;copy&amp;quot; of the object; if the object will change inside the bridge, expecco will still present the old state.&lt;br /&gt;
&lt;br /&gt;
== I get Timeouts - how can I change the Defaults ? ==&lt;br /&gt;
There is currently no dialog to change the default settings (except for the CBridge in v23.1). &lt;br /&gt;
&lt;br /&gt;
However, the default values which control the timeouts can be changed via Smalltalk expressions (or corresponding JavaScript expressions).&lt;br /&gt;
&amp;lt;br&amp;gt;To set a common default for all Python, CBridge and NodeJS bridge&amp;lt;br&amp;gt;In Smalltalk syntax:&lt;br /&gt;
 SimpleBridge connectTimeout: &#039;&#039;seconds&#039;&#039;.     &lt;br /&gt;
 SimpleBridge defineAckTimeoutMS: &#039;&#039;millis&#039;&#039;.  &lt;br /&gt;
 SimpleBridge executeAckTimeoutMS: &#039;&#039;millis&#039;&#039;.&lt;br /&gt;
or in JavaScript syntax:&lt;br /&gt;
 SimpleBridge.connectTimeout(&#039;&#039;seconds&#039;&#039;);     &lt;br /&gt;
 SimpleBridge.defineAckTimeoutMS(&#039;&#039;millis&#039;&#039;);  &lt;br /&gt;
 SimpleBridge.executeAckTimeoutMS(&#039;&#039;millis&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
We are sorry for the inconsistent argument (seconds vs. milliseconds); these result from history and later added features. We will provide a consistent interface in later versions.&lt;br /&gt;
 &lt;br /&gt;
To set the default for individual language bridges:&lt;br /&gt;
 PythonBridge connectTimeout: &#039;&#039;seconds&#039;&#039;.      &lt;br /&gt;
 PythonBridge defineAckTimeoutMS: &#039;&#039;millis&#039;&#039;.  &lt;br /&gt;
 PythonBridge executeAckTimeoutMS: &#039;&#039;millis&#039;&#039;. &lt;br /&gt;
 &lt;br /&gt;
 CBridge connectTimeout: &#039;&#039;seconds&#039;&#039;.      &lt;br /&gt;
 CBridge defineAckTimeoutMS: &#039;&#039;millis&#039;&#039;.  &lt;br /&gt;
 CBridge executeAckTimeoutMS: &#039;&#039;millis&#039;&#039;. &lt;br /&gt;
 &lt;br /&gt;
 NodeJSBridge connectTimeout: &#039;&#039;seconds&#039;&#039;.      &lt;br /&gt;
 NodeJSBridge defineAckTimeoutMS: &#039;&#039;millis&#039;&#039;.  &lt;br /&gt;
 NodeJSBridge executeAckTimeoutMS: &#039;&#039;millis&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
You can retrieve the default values via corresponding getter messages:&lt;br /&gt;
 &amp;lt;someBridgeClass&amp;gt; connectTimeout =&amp;gt; that bridge type&#039;s connectTimeout&lt;br /&gt;
 &amp;lt;someBridgeClass&amp;gt; defineAckTimeoutMS =&amp;gt; that bridge type&#039;s defineAckTimeout in milliseconds&lt;br /&gt;
 &amp;lt;someBridgeClass&amp;gt; executeAckTimeoutMS =&amp;gt; that bridge type&#039;s executeAckTimeout in milliseconds&lt;br /&gt;
&lt;br /&gt;
&amp;quot;connectTimeout&amp;quot; is relevant, when connecting to a remote machine;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;quot;defineAckTimeoutMS&amp;quot; is the time expecco will wait for a confirmation after an action&#039;s code has been transferred to the bridge;&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;quot;executeAckTimeoutMS&amp;quot; is the time expecco waits for an acknowledge after sending an action-step&#039;s data (pin values). See note below. &lt;br /&gt;
&lt;br /&gt;
To be effective, these default values must be set before a bridge connection is setup.&lt;br /&gt;
You can either place these expressions into the &amp;quot;startup.rc&amp;quot; file (in the expecco installation folder), or into a test suite as an elementary (Smalltalk or JavaScript) action which is executed as post-load action or as a prepare action of a testplan.&lt;br /&gt;
&lt;br /&gt;
The above control the default values for new bridge connections. You can also change an existing connection&#039;s parameter by sending the same messages to a concrete bridge.&lt;br /&gt;
&lt;br /&gt;
Expecco 21.2: &lt;br /&gt;
:You may have to adjust the executeAckTimeout, if huge amounts of data are transfered.&lt;br /&gt;
:(we encountered this limit eg. when transferring a vector of 1 mio floats to the bridge)&lt;br /&gt;
Expecco 22.1:&lt;br /&gt;
:Expecco adjusts this automatically to match the amount of data.&lt;br /&gt;
&lt;br /&gt;
== I don&#039;t see the difference between DLL actions and bridged C-actions; when to use which? ==&lt;br /&gt;
&lt;br /&gt;
DLL action blocks - when executed - will ensure that the specified DLL (shared object) is loaded into the running expecco program and directly called from within expecco. In other words: it executes in the same address space as expecco.&lt;br /&gt;
&lt;br /&gt;
On the other hand, C-Bridge actions are executed by a separate program (the &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;) and expecco communicates with that program via a socket connection.&lt;br /&gt;
&lt;br /&gt;
Both mechanisms have advantages and disadvantages:&lt;br /&gt;
&lt;br /&gt;
DLL actions:&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; very fast call (no remote procedure call)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; very fast data transmission (especially, big vectors can be passed quickly)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; can be used if only the binary is present and no compiler toolchain is needed/wanted&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; the called code may crash the expecco executable if it misbehaves or is provided with wrong arguments&amp;lt;BR&amp;gt;(notice: although expecco tries to catch any illegal memory references, it may still happen, that a called DLL-function misbehaves and overwrites/manipulates memory which it is not supposed to. For example, if it overwrites any data of expecco, there may be a later crash in expecco.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; the called code may block expecco or slow down the user interface&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; the called code may exit/terminate the current thread or the program and thus terminate expecco (i.e. make sure, it does not call &amp;quot;&amp;lt;code&amp;gt;exit()&amp;lt;/code&amp;gt;&amp;quot;). Although expecco sets the &amp;quot;atexit&amp;quot; handler, shared libraries may still find other means to terminate.&lt;br /&gt;
&lt;br /&gt;
Bridged Calls:&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; code runs completely isolated from expecco - the bridge may crash due to bad data or a bad library call, but expecco will remain alive. You&#039;ll get a fail-status of the corresponding action in expecco.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; additional data conversions or checks are easily added (in case the called function&#039;s interface requires complicated object structures, such as complex structures/unions, pointers to pointers, pointers to return values etc.)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; better support for debugging (writing log-entries, adding printfs or running the cBridge under a debugger)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; the expecco UI will not be blocked by a runaway bridged action&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; the bridged action can be executed on the local or on a remote machine&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; the bridged action can be executed on a different operating system or CPU architecture (eg. expecco runs on a Linux machine, the bridge on Windows or even in a RasperryPI)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(+)&#039;&#039;&#039; multiple bridged C actions can execute in parallel on multiple machines or in multiple processes on one machine&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; the round trip times are quite long compared to direct DLL calls (in the order of milliseconds, in contrast to direct DLL calls, which run in the order of nanoseconds)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; multiple round trips if many fields of returned object references have to be accessed&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;(-)&#039;&#039;&#039; a C-compiler toolchain is needed (on the local or the target system, where the bridged C code is to be executed)&lt;br /&gt;
  &lt;br /&gt;
Despite the above mentioned performance differences, we highly recommend to use bridged C actions instead of direct DLL calls, iff the performance/round trip times are acceptable. The added safety due to the process boundaries makes it much easier to develop and maintain those.&lt;br /&gt;
&lt;br /&gt;
== How can I debug the code in the bridge ==&lt;br /&gt;
Expecco does include some limited debugging support for bridged code, but the level of support is different between individual bridges:&lt;br /&gt;
* Python, Node, Smalltalk, Groovy&amp;lt;br&amp;gt;Support breakpoints and single stepping. Walkback and some access to remote objects.&lt;br /&gt;
* C&amp;lt;br&amp;gt;Walkback and some access to remote objects. &lt;br /&gt;
&lt;br /&gt;
To debug bridged C-code, we recommend executing the bridge inside a debugger; for example, under Unix, you would compile your framework with the &amp;quot;-g&amp;quot; (debug) option, then open a shell terminal window and start the bridge under a debugger (say &amp;quot;lldb&amp;quot; or &amp;quot;gdb&amp;quot;) with:&lt;br /&gt;
 lldb cBridge&lt;br /&gt;
 &amp;gt;&amp;gt; r --server --port 8899&lt;br /&gt;
then change the expecco settings for the CBridge to &amp;quot;&#039;&#039;Connect to an already running bridge&#039;&#039;&amp;quot; and also define the port  there. Expecco will then connect to your debugged bridge instead of starting one itself.&lt;br /&gt;
A similar setup is to be used when debugging with Eclipse or Visual Studio on Windows. &lt;br /&gt;
&lt;br /&gt;
To debug Python code, you can check the &amp;quot;&#039;&#039;Disable Debugger&#039;&#039;&amp;quot; flag in the Python settings, and attach a Python debugger (eg. VSCode) to the running Python process.&lt;br /&gt;
&lt;br /&gt;
== Security Considerations ==&lt;br /&gt;
Make sure that remote bridges are only reachable from inside your local network and only from trusted hosts. You should configure your firewall as appropriate, or run tests in an isolated network. You may also configure switches and routers to limit access, or use a secondary interface (alternative lan or wifi).&lt;br /&gt;
&lt;br /&gt;
Another recommened option is to setup an ssh tunnel for the particular port(s) in question.&lt;br /&gt;
&lt;br /&gt;
All bridges support command line arguments to only accept connections from a particular host; this option should be used if a remote bridge is started via a remote shell command.&lt;br /&gt;
&lt;br /&gt;
=== SSL/TLS Encrypted Connections ===&lt;br /&gt;
All bridges support SSL/TLS encrypted connections. This provides both confidentiality and (with mutual TLS) authentication.&lt;br /&gt;
&lt;br /&gt;
To enable SSL for a bridge connection, configure the following in the expecco bridge settings:&lt;br /&gt;
* &#039;&#039;&#039;Use SSL&#039;&#039;&#039;: enable TLS encryption&lt;br /&gt;
* &#039;&#039;&#039;Certificate File&#039;&#039;&#039;: PEM file containing the server certificate and private key (used by the bridge process)&lt;br /&gt;
* &#039;&#039;&#039;Client Certificate File&#039;&#039;&#039;: PEM file containing the client certificate and private key (presented to servers that require client authentication)&lt;br /&gt;
&lt;br /&gt;
Certificate generation is built into the cBridge and Python bridge executables using Ed25519 keys:&lt;br /&gt;
 cBridge --generateCA ca.pem --cn &amp;quot;My CA&amp;quot;&lt;br /&gt;
 cBridge --generateCert server.pem --ca ca.pem --cn myhost&lt;br /&gt;
 cBridge --generateCert client.pem --ca ca.pem --cn expecco&lt;br /&gt;
&lt;br /&gt;
Generated PEM files include the full certificate chain, so the CA is automatically trusted without additional configuration.&lt;br /&gt;
&lt;br /&gt;
For mutual TLS (mTLS), start the remote bridge with the &amp;lt;code&amp;gt;--clientAuth&amp;lt;/code&amp;gt; flag:&lt;br /&gt;
 cBridge --port 8855 --ssl --cert server.pem --clientAuth&lt;br /&gt;
&lt;br /&gt;
See [[Cbridge_setup#SSL/TLS_Connection_to_a_Remote_CBridge|CBridge Setup: SSL/TLS Connection]] for detailed instructions.&lt;br /&gt;
&lt;br /&gt;
== File Transfer and Remote Directory Operations ==&lt;br /&gt;
All bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk) support transferring files between expecco and the remote bridge:&lt;br /&gt;
* &amp;lt;code&amp;gt;putFile: localPath to: remotePath&amp;lt;/code&amp;gt; — upload a file to the bridge&lt;br /&gt;
* &amp;lt;code&amp;gt;getFile: remotePath to: localPath&amp;lt;/code&amp;gt; — download a file from the bridge&lt;br /&gt;
* &amp;lt;code&amp;gt;makeDirectory: remotePath&amp;lt;/code&amp;gt; — create a directory (including parent directories) on the bridge&lt;br /&gt;
&lt;br /&gt;
These operations use the existing bridge connection and work over SSL if enabled. They are useful for deploying test data, collecting results, or transferring compiled binaries.&lt;br /&gt;
&lt;br /&gt;
== [OS X Only] CrashReporter Dialog Boxes ==&lt;br /&gt;
You may get annoying dialog boxes telling about &amp;quot;&#039;&#039;Unexpected Termination&#039;&#039;&amp;quot; whenever a bridge is hard terminated via the &amp;quot;&#039;&#039;Terminate&#039;&#039;&amp;quot; button in the debugger.&lt;br /&gt;
&lt;br /&gt;
This is a &amp;quot;&#039;&#039;feature&#039;&#039;&amp;quot; of the OS X system, not controlled by expecco.&lt;br /&gt;
&lt;br /&gt;
You can disable this by executing the following command in a console terminal:&lt;br /&gt;
 defaults write com.apple.CrashReporter DialogType none&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Back to [[FAQ/en | FAQ]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Cbridge_setup&amp;diff=31328</id>
		<title>Cbridge setup</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Cbridge_setup&amp;diff=31328"/>
		<updated>2026-05-27T07:01:30Z</updated>

		<summary type="html">&lt;p&gt;Sv: document SSL/TLS, certificate generation, mTLS, file transfer, makeDirectory&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= CBridge Setup =&lt;br /&gt;
&lt;br /&gt;
In order to compile and execute C/C++ actions, a C compiler toolchain has to be installed on the machine, where the Bridge executable (Windows: &amp;lt;code&amp;gt;cBridge.exe&amp;lt;/code&amp;gt; / Unix: &amp;lt;code&amp;gt;cBridge&amp;lt;/code&amp;gt;) runs.&lt;br /&gt;
&amp;lt;br&amp;gt;Typically this is the local machine on which expecco runs, but it may be any other machine in your reachable network.&lt;br /&gt;
&amp;lt;br&amp;gt;The CPU architecture and or operating system may be (and often is) different from the CPU which executes expecco, therefore the C-code is compiled on the target machine (i.e. not cross-compiled).&lt;br /&gt;
&lt;br /&gt;
== C-Compiler Toolchain Installation ==&lt;br /&gt;
&lt;br /&gt;
=== Windows + Borland Compiler (32bit) ===&lt;br /&gt;
The compiler is a bit outdated, but still free and useful.&amp;lt;br&amp;gt;However, it only supports 32bit programs. Thus, it cannot be used if you need access to 64bit dlls.&amp;lt;br&amp;gt;(on the other hand, if you need to interact with a 32bit dll to communicate with some hardware device, you&#039;ll must use a 32bit cBridge).&lt;br /&gt;
&lt;br /&gt;
We recommend to install the toolchain at its default installation path (typically &amp;quot;&amp;lt;code&amp;gt;C:\borland&amp;lt;/code&amp;gt;&amp;quot;). Then, the provided cc-compile script for borland can be used unchanged.&lt;br /&gt;
&lt;br /&gt;
=== Windows + MINGW Compiler (32 or 64bit) ===&lt;br /&gt;
The mingw toolchain is based on the gcc compiler. This is recommended and preferred over borland.&lt;br /&gt;
&lt;br /&gt;
=== Windows + Microsoft Visual C / Visual Studio === &lt;br /&gt;
There is no need to install the full Visual Studio IDE. Only the C-compiler, linker and libraries are required. &lt;br /&gt;
Thus, you can untoggle all additional optional packages during the installation.&lt;br /&gt;
&lt;br /&gt;
Check for the &amp;quot;&amp;lt;code&amp;gt;cl&amp;lt;/code&amp;gt;&amp;quot; command (being in your &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt;) or find and remember the path to it (typically somewhere under &amp;quot;&amp;lt;code&amp;gt;c:\Program Files\Microsoft\...&amp;lt;/code&amp;gt;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
=== Unix / Linux ===&lt;br /&gt;
Install whatever packages are required; check if the &amp;quot;&amp;lt;code&amp;gt;cc&amp;lt;/code&amp;gt;&amp;quot; command is found along your &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; (before starting expecco),&lt;br /&gt;
or alternatively, remember the path to the &amp;quot;&amp;lt;code&amp;gt;cc&amp;lt;/code&amp;gt;&amp;quot; command.&lt;br /&gt;
 &lt;br /&gt;
Regardless of which compiler you use, &lt;br /&gt;
please remember the installation path. You will need it later unless the compiler is found along your &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Quick Check if it Already Works ==&lt;br /&gt;
We provide a number of setups for common installations.&lt;br /&gt;
In many situations, this will already be correct for your setup.&lt;br /&gt;
&lt;br /&gt;
To check, create a new elementary-bridgedC action, and run it.&lt;br /&gt;
(the initial tree which is created with examples also contains a simple C action).&lt;br /&gt;
&lt;br /&gt;
If you get a green OK result, you&#039;re already done.&lt;br /&gt;
If not, your setup needs to be adjusted.&lt;br /&gt;
&lt;br /&gt;
Read the chapter at the end of this page on step-by-step setup verification.&lt;br /&gt;
&lt;br /&gt;
== The Compile Script ==&lt;br /&gt;
For compilation, the cBridge program calls a batch/shell script, which is responsible for compilation of the C-code to a DLL/shared object file.&lt;br /&gt;
This script may need to be edited.&lt;br /&gt;
We recommend, that you navigate to the folder where the cBridge executable is located, take one of the existing scripts as template, make a copy under a new name, and then edit this copy to suit your needs.&lt;br /&gt;
&lt;br /&gt;
Take one of the existing scripts which uses the same compiler (borland/mingw/visualC).&lt;br /&gt;
&lt;br /&gt;
In the editor, check the &amp;lt;code&amp;gt;PATH&amp;lt;/code&amp;gt; setting, and edit it as appropriate, finally save it.&lt;br /&gt;
&lt;br /&gt;
Back in expecco, go to the cBridge settings under the external-script settings,&lt;br /&gt;
and change the CC-script setting there (&amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Shutdown any already running bridge (&amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Debugging&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Shutdown all Bridge Connections&#039;&#039;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Go back to the C-action and repeat the quick check.&lt;br /&gt;
&lt;br /&gt;
Eventually, you should see a green OK result.&lt;br /&gt;
&lt;br /&gt;
== Special Additional Libraries ==&lt;br /&gt;
&lt;br /&gt;
It may be required that your C-code needs additional shared libraries to be linked against your code.&lt;br /&gt;
The easiest is to add those libraries and corresponding command line options to the CC-script&#039;s compiler call command.&lt;br /&gt;
The details depend on the compiler used.&lt;br /&gt;
You may need to do a &amp;quot;&amp;lt;code&amp;gt;cc --help&amp;lt;/code&amp;gt;&amp;quot;, &amp;quot;&amp;lt;code&amp;gt;cl/help&amp;lt;/code&amp;gt;&amp;quot; or similar, to figure out which command line options are required.&lt;br /&gt;
&lt;br /&gt;
= Remote C-Bridges =&lt;br /&gt;
You can run any number of cBridges on any machine within your network (and also multiple cBridges on your local or a remote machine), and execute C-actions there. For this, the following setup steps are to be performed:&lt;br /&gt;
&lt;br /&gt;
* copy the cbridge executable and its support files to a new folder on the target machine; the files are found below the expecco installation folder&amp;lt;br&amp;gt;(eg. &amp;quot;&amp;lt;code&amp;gt;c:\Program Files\exept\expecco&amp;lt;/code&amp;gt;&amp;quot;) in &amp;quot;&amp;lt;code&amp;gt;packages\bridgeFramework\cBridge\cLibrary&amp;lt;/code&amp;gt;&amp;quot;.&lt;br /&gt;
:The easiest way is to copy the whole folder. Make sure that the copied folder matches the target machine&#039;s architecture (i.e. if the target is a Linux machine, you must obviously copy the files from a Linux installation, and same so for Windows machines).&lt;br /&gt;
&lt;br /&gt;
* on the remote machine, make sure that the cBridge is running; either by executing a remote command from inside your expecco suite, or by adding the cBridge startup to a cron tab (Unix/Linux) or the service list or autoexec.bat (Windows).&lt;br /&gt;
:As a test, start it manually with: &amp;quot;&amp;lt;code&amp;gt;cBridge --port 8856&amp;lt;/code&amp;gt;&amp;quot;, and connect to it from expecco (change the settings (&amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; - &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;) to connect to an already running cBridge at that port).&lt;br /&gt;
&lt;br /&gt;
* if in doubt, start the cBridge with a &amp;quot;&amp;lt;code&amp;gt;--help&amp;lt;/code&amp;gt;&amp;quot; option.&lt;br /&gt;
&lt;br /&gt;
=== CBridge Command Line Arguments ===&lt;br /&gt;
&lt;br /&gt;
* --help&amp;lt;br&amp;gt;Prints a list of the supported comamnd line arguments&lt;br /&gt;
* --localOnly&amp;lt;br&amp;gt;only accept connections from the local machine&lt;br /&gt;
* --host &#039;&#039;hostname&#039;&#039;&amp;lt;br&amp;gt;connect to that host instead of waiting for incoming connections&lt;br /&gt;
* --port&amp;lt;br&amp;gt;the TCP port on which the bridge is waiting for incoming requests or connecting to (with --host argument)&lt;br /&gt;
* -- keepAlive&amp;lt;br&amp;gt;after the first connection, keep on waiting for more incoming connections. Without this, the bridge will only handle a single session and exit after that.&lt;br /&gt;
* --log&amp;lt;br&amp;gt;log actions on stderr&lt;br /&gt;
* --log2&amp;lt;br&amp;gt;even more detailed log&lt;br /&gt;
* --ccScript &#039;&#039;scriptFile&#039;&#039;&amp;lt;br&amp;gt;Use the given script file (a shell or batch script) to compile&lt;br /&gt;
* --includes &#039;&#039;files&#039;&#039;&amp;lt;br&amp;gt;Additional include folders passed to the compile script&lt;br /&gt;
* --dlls &#039;&#039;files&#039;&#039;&amp;lt;br&amp;gt;Additional dlls (shared libraries) to be linked against actions&lt;br /&gt;
* --testCompile&amp;lt;br&amp;gt;For a standalone selftest if compilation  works. Compiles a dummy almost empty source file&lt;br /&gt;
&lt;br /&gt;
More arguments may be recognized, depending on the cBridge version. Use &amp;quot;--help&amp;quot; to see more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== SSL/TLS Connection to a Remote CBridge ===&lt;br /&gt;
&lt;br /&gt;
The cBridge supports encrypted TLS connections with optional mutual certificate authentication (mTLS).&lt;br /&gt;
&lt;br /&gt;
==== Generating Certificates ====&lt;br /&gt;
The cBridge can generate Ed25519 CA and server/client certificates directly:&lt;br /&gt;
&lt;br /&gt;
 cBridge --generateCA ~/.ssl/ca.pem --cn &amp;quot;My CA&amp;quot; --days 3650&lt;br /&gt;
 cBridge --generateCert ~/.ssl/server.pem --ca ~/.ssl/ca.pem --cn myhost&lt;br /&gt;
 cBridge --generateCert ~/.ssl/client.pem --ca ~/.ssl/ca.pem --cn expecco&lt;br /&gt;
&lt;br /&gt;
Each generated PEM file contains the certificate, private key, and the CA certificate chain. The &amp;lt;code&amp;gt;--cn&amp;lt;/code&amp;gt; option sets the common name (default: localhost), &amp;lt;code&amp;gt;--days&amp;lt;/code&amp;gt; sets the validity period (default: 3650).&lt;br /&gt;
&lt;br /&gt;
The same certificate generation is also available via the Python bridge script (&amp;lt;code&amp;gt;--generateCA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;--generateCert&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Starting the CBridge with SSL ====&lt;br /&gt;
&lt;br /&gt;
 cBridge --port 8855 --ssl --cert ~/.ssl/server.pem&lt;br /&gt;
&lt;br /&gt;
A combined PEM file (certificate + key in one file) is used by default. Separate files are also supported:&lt;br /&gt;
&lt;br /&gt;
 cBridge --port 8855 --ssl --cert server.crt --key server.key&lt;br /&gt;
&lt;br /&gt;
==== Mutual TLS (Client Certificate Authentication) ====&lt;br /&gt;
&lt;br /&gt;
To require clients to present a certificate signed by the same CA:&lt;br /&gt;
&lt;br /&gt;
 cBridge --port 8855 --ssl --cert ~/.ssl/server.pem --ca ~/.ssl/ca.pem --clientAuth&lt;br /&gt;
&lt;br /&gt;
Clients must then be configured with a client certificate (see the expecco CBridge settings dialog).&lt;br /&gt;
&lt;br /&gt;
==== Expecco Settings for SSL ====&lt;br /&gt;
&lt;br /&gt;
In expecco, configure the CBridge connection under &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;:&lt;br /&gt;
* &#039;&#039;&#039;Use SSL&#039;&#039;&#039;: enable encrypted connection&lt;br /&gt;
* &#039;&#039;&#039;Certificate File&#039;&#039;&#039;: the server certificate PEM (for the bridge process)&lt;br /&gt;
* &#039;&#039;&#039;Client Certificate File&#039;&#039;&#039;: the client certificate PEM (presented to the server for mTLS)&lt;br /&gt;
&lt;br /&gt;
When the client certificate PEM includes the CA certificate in the chain, the CA is automatically trusted for server certificate verification.&lt;br /&gt;
&lt;br /&gt;
==== File Transfer and Directory Operations ====&lt;br /&gt;
All bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk) support file transfer to and from the remote bridge:&lt;br /&gt;
* &amp;lt;code&amp;gt;putFile: localPath to: remotePath&amp;lt;/code&amp;gt; — upload a file&lt;br /&gt;
* &amp;lt;code&amp;gt;getFile: remotePath to: localPath&amp;lt;/code&amp;gt; — download a file&lt;br /&gt;
* &amp;lt;code&amp;gt;makeDirectory: remotePath&amp;lt;/code&amp;gt; — create a directory (including parent directories)&lt;br /&gt;
&lt;br /&gt;
These operations work over the bridge&#039;s existing connection (including SSL if enabled).&lt;br /&gt;
&lt;br /&gt;
= Step-by-Step Problem Finding/Fixing =&lt;br /&gt;
&lt;br /&gt;
=== Ensure that the cBridge executable is present and can be executed ===&lt;br /&gt;
* goto the expecco installation folder (typically somewhere under &amp;quot;&amp;lt;code&amp;gt;c:\Program Files\exept\expecco\&amp;lt;/code&amp;gt;&amp;quot;), and look for files named &amp;quot;&amp;lt;code&amp;gt;cBridge.exe&amp;lt;/code&amp;gt;&amp;quot; or &amp;quot;&amp;lt;code&amp;gt;cBridge32.exe&amp;lt;/code&amp;gt;&amp;quot; or &amp;quot;&amp;lt;code&amp;gt;cBridge&amp;lt;/code&amp;gt;&amp;quot; (under Unix/Linux). It is typically found in a sub folder named &amp;quot;&amp;lt;code&amp;gt;packages/expecco/bridgeFramework/cBridge&amp;lt;/code&amp;gt;&amp;quot;.&lt;br /&gt;
* open a shell- or cmd window (and navigate there).&lt;br /&gt;
* type &amp;quot;&amp;lt;code&amp;gt;cBridge --help&amp;lt;/code&amp;gt;&amp;quot; (with powershell: &amp;quot;&amp;lt;code&amp;gt;.\cBridge --help&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
:: if that fails (does not output some useful help text), make sure that it can be executed.&amp;lt;br&amp;gt;Maybe your security policy is too strict ot the installation is incomplete.&lt;br /&gt;
* start the bridge with &amp;quot;&amp;lt;code&amp;gt;cBridge --log&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
:: it should output some messages, the last being &amp;quot;&amp;lt;code&amp;gt;... listening on port xxxx&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
* if the cBridge is to run on a machine different from the one expecco is running on, make sure that the firewall allows for connections between the two machines (at the desired port nr)&lt;br /&gt;
* if required, use another port (i.e. run it with &amp;quot;&amp;lt;code&amp;gt;cBridge --log --port &amp;lt;Nr&amp;gt;&amp;lt;/code&amp;gt;&amp;quot;)&lt;br /&gt;
:: now we have a cBridge running, ready to accept connections from expecco at the given port nr.&lt;br /&gt;
* keep the shell/cmd window open; we will need it later (and also to see any diagnostic output)&lt;br /&gt;
&lt;br /&gt;
=== Ensure that the cBridge is reachable from expecco ===&lt;br /&gt;
for this, we first try to connect to that already running bridge (instead of letting expecco start it itself)&lt;br /&gt;
* in expecco, open the settings and navigate to the cBridge settings: &lt;br /&gt;
:: &amp;quot;&#039;&#039;Extras&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Settings&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;Execution&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;External Script Interpreters&#039;&#039;&amp;quot; &amp;amp;rarr; &amp;quot;&#039;&#039;CBridge&#039;&#039;&amp;quot;&lt;br /&gt;
* check the &amp;quot;&#039;&#039;Connect to already Running Bridge&#039;&#039;&amp;quot; box.&lt;br /&gt;
:: enter CBridge Host and Port as &amp;quot;&amp;lt;code&amp;gt;localhost&amp;lt;/code&amp;gt;&amp;quot; and the above port number (default is 8855)&lt;br /&gt;
* close the settings dialog (without saving the settings for now, when asked)&lt;br /&gt;
* open a new project.&amp;lt;br&amp;gt;The default project will contain a sample &amp;quot;Hello World&amp;quot; C-action, which can be used for the smoke test.&lt;br /&gt;
* in the expecco tree, find the &amp;quot;&amp;lt;code&amp;gt;Simple Elementary Action (C)&amp;lt;/code&amp;gt;&amp;quot; (under the &amp;quot;Activities&amp;quot; group).&lt;br /&gt;
* run it&lt;br /&gt;
:: if the error states that no connection could be setup, check your security policy, firewall etc. and repeat&lt;br /&gt;
:: if the error states that the compilation failed, the bridge connection works, but the compilation script setup is wrong. Proceed.&lt;br /&gt;
&lt;br /&gt;
=== Ensure that the compilation works ===&lt;br /&gt;
the cBridge needs a C-compiler for its operation; to verify,&lt;br /&gt;
* stop the manually started C-bridge (in the shell/cmd window) by pressing CTRL-C there&lt;br /&gt;
* depending on the C-compiler you intend to use, one of the &amp;quot;compile_xxx.bat&amp;quot; or &amp;quot;compile_xxx.sh&amp;quot; script files will be used. The task to be performed by these scripts is to compile a given C-file.&lt;br /&gt;
* check which compiler you installed and intent to use (MSVC, Mingw, gcc, clang or bcc), and look for a corresponding script file.&lt;br /&gt;
* check if the compiler is correctly installed (especially MSVC and MINGW sometimes make trouble here).&lt;br /&gt;
:: one particular problem with MSVC is when deinstalling and reinstalling another version. There seem to be leftover files and/or registry entries which may break the installation (this happend to one of our customers, and also to us when upgrading)&lt;br /&gt;
* Enter the compile-command (&amp;quot;cl&amp;quot;, &amp;quot;cc&amp;quot;, &amp;quot;gcc&amp;quot; or &amp;quot;clang&amp;quot;) on a command line (cmd or shell)&lt;br /&gt;
:: check that you get an answer&lt;br /&gt;
:: try to compile a one-liner (eg. &amp;quot;&amp;lt;code&amp;gt;main() { printf(&amp;quot;hello\n&amp;quot;); }&amp;lt;/code&amp;gt;&amp;quot; and run it to see if it links correctly. Run it!&lt;br /&gt;
* check if the bridge&#039;s cc script file works by running &amp;quot;&amp;lt;code&amp;gt;cBridge --log --ccScript &amp;lt;scriptfilename&amp;gt; --testCompile&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
:: if required, make a copy of one of the script files (the one you think is best to start with) and fix any path inside. If required, add echo statements to show what is going on. Keep the original script and create a new one.&lt;br /&gt;
:: under Windows: in the script, the PATH to the compiler is typically searched and set; for example by calling the vcvarsall.bat script which is provided by microsoft. If required, change the line which calls this (you can also add this batch-call to your autoexec.bat and remove the line from the script). In any case: at the end, the &amp;quot;cl&amp;quot; command should be found along your path. &lt;br /&gt;
* the --testCompile will generate a piece of code which outputs &amp;quot;here is foo&amp;quot;; i.e. on your system (we use mingw), the command is &amp;quot;&amp;lt;code&amp;gt;cBridge --log --ccScript compile_windows_mingw.bat&amp;quot; --testCompile&amp;lt;/code&amp;gt;&amp;quot;, and the output is &amp;quot;here is foo&amp;quot; - &amp;quot;void pointer size: 8&amp;quot;, followed by the usual &amp;quot;listening on port&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
=== Change the Settings in expecco ===&lt;br /&gt;
* open the cBridge settings again&lt;br /&gt;
* uncheck the &amp;quot;&#039;&#039;Connect to already running bridge&#039;&#039;&amp;quot; box&lt;br /&gt;
* enter the name of the compile script into the &amp;quot;CC-script&amp;quot; field (possibly the name of the new script)&lt;br /&gt;
* shutdown any already running bridge&lt;br /&gt;
* try executing the expecco-C action again&lt;br /&gt;
* if you get a green outcome, save your expecco settings.&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31321</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31321"/>
		<updated>2026-05-26T18:52:47Z</updated>

		<summary type="html">&lt;p&gt;Sv: Fold the Automatic-Refresh bullets onto single physical lines&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on OpenSSL or libssh.  Use this for anything that touches credentials or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine. Used for local-tool integration and for the local end of a remote workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No encryption, passwords on the wire in clear.  Use only when the target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
&amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt; subclass that lets the rest of ST/X treat a remote SFTP path the same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Refresh&#039;&#039;&#039; button in the toolbar (the round-arrow icon&lt;br /&gt;
between &#039;&#039;Forward&#039;&#039; and &#039;&#039;DirectoryUp&#039;&#039;) re-reads both the&lt;br /&gt;
directory tree and the contents pane on demand.  Works uniformly&lt;br /&gt;
for local and SFTP paths; for SFTP it also flushes the per-file&lt;br /&gt;
STAT cache, so changes made directly on the remote side become&lt;br /&gt;
visible immediately rather than waiting for the 5-second cache TTL&lt;br /&gt;
to expire.&lt;br /&gt;
&lt;br /&gt;
The small arrow next to the Refresh icon opens a dropdown with a&lt;br /&gt;
single checkbox, &#039;&#039;&#039;Automatic Refresh&#039;&#039;&#039;, controlling the&lt;br /&gt;
background polling task that walks every expanded tree item to&lt;br /&gt;
detect external changes.  The default depends on the current root:&lt;br /&gt;
&lt;br /&gt;
* Local filesystem &amp;amp;rarr; &#039;&#039;&#039;on&#039;&#039;&#039; (10-second cycle, matches the long-standing behaviour).&lt;br /&gt;
* SFTP &amp;amp;rarr; &#039;&#039;&#039;off&#039;&#039;&#039;.  Each cycle costs one STAT round-trip per child, which is fine for a handful of local directories but painful over the network.  Click Refresh manually when you need to pick up remote changes.&lt;br /&gt;
&lt;br /&gt;
When you navigate between local and SFTP roots the toggle flips&lt;br /&gt;
automatically &amp;amp;mdash; but only if you haven&#039;t overridden it for&lt;br /&gt;
the previous root.  An explicit user choice is preserved across&lt;br /&gt;
navigations.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of the filesystem holding the currently displayed directory.  Works uniformly for local paths and SFTP paths; for SFTP it requires the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; extension (every modern OpenSSH does).  Sizes are reported in IEC binary units (MiB, GiB, TiB) — the largest unit yielding a value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039; rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
&amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only; gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file unencrypted (agent-only mode ignores the passphrase, since the OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to &#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally; a ST/X on the Windows side does not.  Bridging needs a helper like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s walkback plus each waiter&#039;s, formatted as plain text.  Use when a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed (e.g. legacy PEM, encrypted-without-agent) — the file is skipped, others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime), no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
[[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every modern OpenSSH does), overwrite is atomic; on the rare server that does not, the receiver is emulated as delete-then-rename and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost three round-trips per directory icon, which made the original tree expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link. Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
&#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer to disk on an open handle.  Available on the low-level&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe, EOF, MNU on nil socket) evicts the dead pool entry, opens a fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP + one SFTP channel per host means N concurrent requests serialise.  Pipelining over multiple SshClients in the pool (preferred), or a transport-level reader process demultiplexing to per-channel inboxes, would let the tree pane keep listing while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (first batch only) + CLOSE — three RTTs per probe; needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style canonicalisation.  (Atomic-overwrite rename is already handled via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension; see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31320</id>
		<title>Remote Access</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31320"/>
		<updated>2026-05-26T18:52:45Z</updated>

		<summary type="html">&lt;p&gt;Sv: Fold the Automatic-Refresh bullets onto single physical lines&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fernzugriff&#039;&#039;&#039; bezeichnet die Möglichkeit, einen entfernten&lt;br /&gt;
Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus&lt;br /&gt;
zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu&lt;br /&gt;
verschieben oder ein Testgerät anzusteuern.  Drei Protokoll-Familien&lt;br /&gt;
sind unterstützt, in absteigender Empfehlungsreihenfolge:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH und SFTP&#039;&#039;&#039; (empfohlen) — verschlüsselte Shell und sichere Dateiübertragung über einen SSH-2-Tunnel.  Reine Smalltalk-Implementierung in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; keine externe Abhängigkeit von OpenSSL oder libssh.  Für alles mit Zugangsdaten oder sensiblen Nutzdaten.&lt;br /&gt;
* &#039;&#039;&#039;Lokale Kommando-Shell&#039;&#039;&#039; — fork + exec auf der lokalen Maschine.  Für die Anbindung lokaler Werkzeuge und für die lokale Seite eines hybriden Workflows.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (veraltet) — Klartext-Terminalsitzung.  Keine Verschlüsselung, Passwörter im Klartext auf der Leitung.  Nur einsetzen, wenn die Gegenstelle keine Alternative bietet.&lt;br /&gt;
&lt;br /&gt;
= SSH und SFTP =&lt;br /&gt;
&lt;br /&gt;
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab&lt;br /&gt;
(RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der&lt;br /&gt;
chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das&lt;br /&gt;
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02).  Zwei Schichten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatischer SSH-Zugriff (entferntes &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY-Shell, Agent-Weiterleitung, ProxyJump-Bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — eine&lt;br /&gt;
&amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;-Unterklasse, die es dem restlichen ST/X&lt;br /&gt;
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale&lt;br /&gt;
Datei.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut:&lt;br /&gt;
zuerst das, was der Anwender sieht und tut, darunter die&lt;br /&gt;
expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails&lt;br /&gt;
für Interessierte.&lt;br /&gt;
&lt;br /&gt;
== Aus dem FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Im Adress-Dropdown eine &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt;-URL einfügen.  Der&lt;br /&gt;
Browser-Tab füllt sich wie bei einem lokalen Pfad.&lt;br /&gt;
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),&lt;br /&gt;
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich&lt;br /&gt;
normal.  Der erste Klick auf einen Host dauert ~200–500 ms&lt;br /&gt;
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte&lt;br /&gt;
Verbindung weiter.&lt;br /&gt;
&lt;br /&gt;
URL-Syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlt &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;, wird der lokale Login-Name verwendet, Port&lt;br /&gt;
ist standardmäßig 22, Pfad standardmäßig &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Die Schaltfläche &#039;&#039;&#039;Refresh&#039;&#039;&#039; in der Symbolleiste&lt;br /&gt;
(Pfeil-Kreis-Symbol zwischen &#039;&#039;Forward&#039;&#039; und &#039;&#039;DirectoryUp&#039;&#039;) liest&lt;br /&gt;
Baum und Inhalts-Panel auf Anforderung neu ein.  Funktioniert&lt;br /&gt;
einheitlich für lokale und SFTP-Pfade; bei SFTP wird zusätzlich der&lt;br /&gt;
per-Datei-STAT-Cache geleert, sodass Änderungen, die direkt auf&lt;br /&gt;
der Gegenseite gemacht wurden, sofort sichtbar werden — ohne auf&lt;br /&gt;
den Ablauf der 5-Sekunden-Cache-TTL zu warten.&lt;br /&gt;
&lt;br /&gt;
Der kleine Pfeil neben dem Refresh-Symbol öffnet ein Aufklappmenü&lt;br /&gt;
mit einem einzelnen Kontrollkästchen, &#039;&#039;&#039;Automatic Refresh&#039;&#039;&#039;, das&lt;br /&gt;
den Hintergrund-Task an- bzw. abschaltet, der alle expandierten&lt;br /&gt;
Baumeinträge auf externe Änderungen prüft.  Die Vorgabe richtet&lt;br /&gt;
sich nach der aktuellen Wurzel:&lt;br /&gt;
&lt;br /&gt;
* Lokales Dateisystem &amp;amp;rarr; &#039;&#039;&#039;an&#039;&#039;&#039; (10-Sekunden-Zyklus, entspricht dem bisherigen Verhalten).&lt;br /&gt;
* SFTP &amp;amp;rarr; &#039;&#039;&#039;aus&#039;&#039;&#039;.  Jeder Zyklus kostet einen STAT-Roundtrip pro Kind — für eine Handvoll lokaler Verzeichnisse harmlos, über das Netz schmerzhaft.  Bei Bedarf manuell auf Refresh klicken, um Änderungen zu sehen.&lt;br /&gt;
&lt;br /&gt;
Beim Wechsel zwischen lokalen und SFTP-Wurzeln wird der Schalter&lt;br /&gt;
automatisch umgelegt &amp;amp;mdash; aber nur, sofern man ihn für die&lt;br /&gt;
vorherige Wurzel nicht selbst verstellt hat.  Eine explizite&lt;br /&gt;
Benutzerwahl bleibt über Navigationen hinweg erhalten.&lt;br /&gt;
&lt;br /&gt;
Das Menü &#039;&#039;&#039;Tools&#039;&#039;&#039; im FileBrowserV2 bietet vier Aktionen — die&lt;br /&gt;
drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek&lt;br /&gt;
sichtbar:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — öffnet den Schlüsselerzeugungs-Dialog, siehe [[#Einen SSH-Schlüssel erzeugen]] unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — öffnet ein interaktives VT100-Terminal zu einem entfernten Host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — navigiert diesen Browser-Tab über SFTP auf ein entferntes Dateisystem.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — zeigt Größe, freien Platz und Belegung des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP setzt der Aufruf voraus, daß der Server die Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; ankündigt (jedes moderne OpenSSH&lt;br /&gt;
tut das).  Größen werden in IEC-Binäreinheiten ausgegeben (MiB,&lt;br /&gt;
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1&lt;br /&gt;
liefert, damit ein TB-großes Volume als &#039;&#039;X TiB&#039;&#039; statt&lt;br /&gt;
&#039;&#039;10240 GiB&#039;&#039; erscheint.&lt;br /&gt;
&lt;br /&gt;
== Aus expecco-Aktionen ==&lt;br /&gt;
&lt;br /&gt;
Das Expecco-RemoteAccess-Plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) stellt folgende Testaktionen&lt;br /&gt;
in der expecco-Aktionspalette bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — öffnet eine SSH-Sitzung über das plattformeigene &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;-Binary (PuTTYs &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; unter Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.&lt;br /&gt;
&lt;br /&gt;
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater&lt;br /&gt;
Schlüssel auf dieser Maschine, öffentlicher Teil in der&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des Zielhosts).  Schlüssel&lt;br /&gt;
erzeugen entweder über den Dialog unten oder über&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Plugin fügt zusätzlich eine Settings-Seite hinzu:&lt;br /&gt;
&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039; mit&lt;br /&gt;
einer einzelnen Schaltfläche &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039;, die&lt;br /&gt;
denselben Dialog öffnet.&lt;br /&gt;
&lt;br /&gt;
== Einen SSH-Schlüssel erzeugen ==&lt;br /&gt;
&lt;br /&gt;
=== Der Dialog (FileBrowserV2 / Settings-Seite) ===&lt;br /&gt;
&lt;br /&gt;
Der Dialog fragt alle Parameter in einem Formular ab:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — wird in den erzeugten Schlüssel eingebettet (Voreinstellung &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — schreibt&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (oder wohin man will) samt&lt;br /&gt;
zugehöriger &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;-Datei daneben.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — schreibt die Datei UND übergibt den Schlüssel dem laufenden ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — der Schlüssel lebt nur im Speicher des Agents; nach Agent-Neustart ist er verloren.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — vollständiger Pfad; ausgegraut im Agent-only-Modus.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — leer lässt die On-Disk-Datei unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten Schlüssel transportiert).&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;Generate&#039;&#039;&#039; wird die Public-Key-Zeile (dieselbe&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt;-Zeichenfolge, die&lt;br /&gt;
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum&lt;br /&gt;
direkten Einfügen in die &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des&lt;br /&gt;
Zielhosts.&lt;br /&gt;
&lt;br /&gt;
=== Aus einem Workspace ===&lt;br /&gt;
&lt;br /&gt;
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; einen reinen Smalltalk-Schlüsselgenerator&lt;br /&gt;
bereit, dessen Ausgabe bit-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt; ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Passphrase-verschlüsselt auf Platte speichern&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ UND in den laufenden Agent laden&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll&lt;br /&gt;
interoperabel (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; rekonstruiert den&lt;br /&gt;
öffentlichen Schlüssel, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; ändert&lt;br /&gt;
die Passphrase usw.).&lt;br /&gt;
&lt;br /&gt;
=== Mit den Shell-Werkzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der klassische Weg funktioniert weiterhin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ssh-agent vorbereiten ==&lt;br /&gt;
&lt;br /&gt;
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien&lt;br /&gt;
deutlich vorzuziehen: er hält verschlüsselte private Schlüssel&lt;br /&gt;
einmal pro Sitzung entsperrt und kann Identitäten verwalten&lt;br /&gt;
(hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X&lt;br /&gt;
nie direkt sehen soll.&lt;br /&gt;
&lt;br /&gt;
ST/X erkennt den Agent-Pfad automatisch, sobald&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;zum Zeitpunkt des Starts von stx&#039;&#039;&#039;&lt;br /&gt;
in der Prozessumgebung gesetzt ist.  Eine spätere Zuweisung aus&lt;br /&gt;
einem Workspace nützt nichts.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Die meisten Desktop-Distributionen starten einen Agent automatisch&lt;br /&gt;
beim Login (gnome-keyring unter GNOME, ssh-agent.service unter&lt;br /&gt;
systemd, KWallet unter KDE).  Prüfen im Terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh oder ähnlich&lt;br /&gt;
ssh-add -l             # listet geladene Identitäten&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # eigene laden, falls nicht da&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei&lt;br /&gt;
aufnehmen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc oder ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X muss aus einer Shell gestartet werden, die diese rc bereits&lt;br /&gt;
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die&lt;br /&gt;
Variable nicht.  Empfehlung: ein kleines Wrapper-Skript unter&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt;, das die rc sourcet und dann stx&lt;br /&gt;
startet.&lt;br /&gt;
&lt;br /&gt;
Die Settings-Seite (&#039;&#039;&#039;Extras → Settings → Plugins → Remote&lt;br /&gt;
Access — SSH Keys&#039;&#039;&#039;) zeigt an, ob das laufende Image einen&lt;br /&gt;
Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Permanente Einrichtung via systemd ====&lt;br /&gt;
&lt;br /&gt;
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-&lt;br /&gt;
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den&lt;br /&gt;
meisten Distros mit dem Paket &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
ausgelieferte Per-User-systemd-Unit aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; in der Shell-rc auf den&lt;br /&gt;
User-Service-Socket zeigen lassen (ersetzt das&lt;br /&gt;
&amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;-Snippet oben):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Um den manuellen &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt;-Schritt zu sparen, kann&lt;br /&gt;
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.&lt;br /&gt;
In &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt; eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und&lt;br /&gt;
übergibt den entsperrten Schlüssel an den Agent; weitere&lt;br /&gt;
Verbindungen nutzen die gespeicherte Identität ohne Prompt.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit.&lt;br /&gt;
Einmalige Einrichtung:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Dienste&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) als Administrator öffnen.&lt;br /&gt;
# &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039; suchen, Starttyp auf &#039;&#039;&#039;Automatisch&#039;&#039;&#039; setzen, &#039;&#039;&#039;Starten&#039;&#039;&#039; anklicken.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Prüfen: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), nicht auf einem&lt;br /&gt;
Unix-Socket.  ST/X unterstützt beide Transporte, jedoch setzt das&lt;br /&gt;
Windows-ssh-add &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; selbst.&lt;br /&gt;
Daher einmalig systemweit setzen:&lt;br /&gt;
&lt;br /&gt;
# {{Key|Win}} drücken → &amp;quot;Umgebungsvariablen&amp;quot; → „Systemumgebungs- variablen bearbeiten&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Umgebungsvariablen&#039;&#039;&#039; → unter &#039;&#039;&#039;Benutzervariablen&#039;&#039;&#039;, &#039;&#039;&#039;Neu&#039;&#039;&#039; klicken.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Wert: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ab- und wieder anmelden (oder stx neu starten), damit die neue Umgebung übernommen wird.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell-Schnelleinrichtung ====&lt;br /&gt;
&lt;br /&gt;
Derselbe Aufbau aus einer &#039;&#039;&#039;Administrator-PowerShell&#039;&#039;&#039; heraus,&lt;br /&gt;
z.B. für Skripte oder unbeaufsichtigte Bereitstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Agent jetzt und bei jedem Neustart starten (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung&lt;br /&gt;
(z.B. Einzelsitzung) die &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt;-Zeile weglassen&lt;br /&gt;
und nur &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt; ausführen.  Die&lt;br /&gt;
env-var-Zeile lässt sich ebenfalls weglassen, wenn&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; nur in der aktuellen Shell gebraucht&lt;br /&gt;
wird — dann statt der &amp;lt;code&amp;gt;[Environment]&amp;lt;/code&amp;gt;-Variante&lt;br /&gt;
&amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Auf stark abgespeckten Windows-Installationen ist der&lt;br /&gt;
ssh-agent-Dienst eventuell nicht vorhanden.  Einmalig nachrüsten&lt;br /&gt;
über &#039;&#039;&#039;Einstellungen → Apps → Optionale Features → OpenSSH-&lt;br /&gt;
Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative Agenten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — eigenes Protokoll; von ST/X&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Agent&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; unterstützt.  Schlüssel zu&lt;br /&gt;
OpenSSH migrieren.&lt;br /&gt;
* &#039;&#039;&#039;Git für Windows ssh-agent&#039;&#039;&#039; — funktioniert;&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; auf den dort veröffentlichten Socket&lt;br /&gt;
zeigen lassen.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — ein ST/X innerhalb der WSL sieht den WSL-eigenen Agent normal; ein ST/X auf der Windows-Seite nicht.  Eine Brücke per &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt; ist möglich.&lt;br /&gt;
&lt;br /&gt;
Prüfung über die Settings-Seite&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
die Anzeige dort meldet, ob das laufende Image den Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Windows-OpenSSH speichert agent-geladene Schlüssel &#039;&#039;&#039;nicht&#039;&#039;&#039;&lt;br /&gt;
über Agent-Neustarts hinweg.  Um nicht nach jedem Reboot manuell&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; aufrufen zu müssen, dieselbe Lazy-Load-&lt;br /&gt;
Konfiguration in &amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;&lt;br /&gt;
eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent&lt;br /&gt;
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige&lt;br /&gt;
Sitzung weiter.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Alle Stellschrauben sind klassenseitig auf&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; erreichbar:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Voreinstellung !! Steuert&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 Min) || Wie lange&lt;br /&gt;
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.&lt;br /&gt;
Liegt knapp unter dem typischen&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; des sshd,&lt;br /&gt;
damit wir uns recyceln, bevor der Server uns mit TCP-RESET&lt;br /&gt;
trennt.  &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; setzt auf Voreinstellung zurück.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Maximales Alter (s)&lt;br /&gt;
eines gecachten STAT, bevor &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; neu am&lt;br /&gt;
Server fragt.  Eltern-listDir stempelt ohnehin frische Attribute&lt;br /&gt;
auf alle Kinder, daher zahlt das Navigieren im offenen&lt;br /&gt;
Verzeichnis das TTL nicht.  &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; schaltet den Cache&lt;br /&gt;
ab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (Aktion) || Reißt jede&lt;br /&gt;
gepoolte Verbindung ab.  Nützlich nach einem bekannt schlechten&lt;br /&gt;
Netzereignis, vor einem bewussten Identitätswechsel oder zum&lt;br /&gt;
sauberen Image-Shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnose ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; über das Untermenü „Status&amp;quot; des&lt;br /&gt;
Launchers öffnen.  Der pro-Host-SFTP-Mutex erscheint als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;, der pool-weite Mutex als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Per Rechtsklick:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — schreibt den Walkback des letzten Eigners samt aller Waiter als Text in die Zwischenablage.  Unverzichtbar, wenn ein Prozess in&lt;br /&gt;
&amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; innerhalb von&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; klemmt.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — die ganze Tabelle, ideal für eine E-Mail-Diagnose.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS über den Wait-for-Graph, meldet Zyklen.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
Interessante Ereignisse werden über &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; geloggt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei automatischem Reconnect nach toter Verbindung.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei Idle-Verdrängung eines Pool-Eintrags.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; wenn eine SSH-Schlüsseldatei nicht geparst werden konnte — die Datei wird übersprungen.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nur SFTP v3.&#039;&#039;&#039;  Kein SETSTAT (kein entferntes chmod / chown / utime), kein SSH_FXP_READLINK exponiert (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; liefert immer &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; die normale stat-Info).  Einige&lt;br /&gt;
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische&lt;br /&gt;
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host.&#039;&#039;&#039;  Zwei gleichzeitige Operationen am selben Host stehen am Host-Mutex an.  Siehe [[#Ausblick]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt;-Fallback hat ein TOCTOU-Fenster.&#039;&#039;&#039; Bei Servern, die &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; ankündigen (jedes moderne OpenSSH tut das), ist das Überschreiben atomar. Beim seltenen Server, der das nicht tut, wird auf Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich dazwischenschieben.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; ist eine Heuristik.&#039;&#039;&#039; Liefert immer &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (die genaue Antwort würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).&lt;br /&gt;
&lt;br /&gt;
== Implementierungsdetails ==&lt;br /&gt;
&lt;br /&gt;
Für Leser, die die Architektur verstehen wollen.  Fünf Klassen,&lt;br /&gt;
von oben nach unten:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Aufgabe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename-Unterklasse, die&lt;br /&gt;
öffentliche API.  Bildet &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt;-URLs auf&lt;br /&gt;
entfernte Dateien ab und stellt &amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; usw. bereit.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3-Protokoll&lt;br /&gt;
(Request/Response-Codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Wird von SftpFilename angesteuert.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH-Kanal-Multiplexer (CHANNEL_OPEN,&lt;br /&gt;
DATA, EOF, CLOSE, WINDOW_ADJUST).  Eine logische Sitzung pro&lt;br /&gt;
Channel-Instanz.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-Level-SSH-Client: öffnet den&lt;br /&gt;
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und&lt;br /&gt;
verteilt anschließend Kanäle.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Drahtschicht.  Banner- und&lt;br /&gt;
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq /&lt;br /&gt;
recvSeq, Heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH-SFTP-Erweiterungen ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst&lt;br /&gt;
minimal gehalten.  OpenSSH bringt einen offenen&lt;br /&gt;
Erweiterungsmechanismus mit: der Server listet im&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;-Reply die Erweiterungsnamen auf, die&lt;br /&gt;
er versteht, und der Client ruft sie über&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt;-Pakete mit dem&lt;br /&gt;
Erweiterungsnamen als erstem String auf.  Jede Erweiterung wird&lt;br /&gt;
über &amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;&lt;br /&gt;
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie&lt;br /&gt;
nicht ankündigt.&lt;br /&gt;
&lt;br /&gt;
Der Stack nutzt heute vier OpenSSH-Erweiterungen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomares rename-mit-Überschreiben.  Wird automatisch von&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt; aufgegriffen; die&lt;br /&gt;
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum&lt;br /&gt;
Einsatz, die die Erweiterung nicht haben.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — Erzeugt einen POSIX-Hardlink. Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX-&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-typische Dateisystem-Statistik.&lt;br /&gt;
Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;;&lt;br /&gt;
das Ergebnis ist form-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;, sodass Aufrufer&lt;br /&gt;
lokale und entfernte Pfade einheitlich behandeln können.&lt;br /&gt;
Treibt den Menü-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; an,&lt;br /&gt;
der am Anfang dieser Seite beschrieben ist.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — schreibt den serverseitigen Schreibpuffer eines geöffneten Handles auf Platte.  Liegt als&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt; bereit; noch nicht&lt;br /&gt;
in eine &amp;quot;Durable-Write&amp;quot;-API auf Filename-Ebene eingebunden.&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden OpenSSH-Erweiterungen&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
werden in der angekündigten Liste erkannt, aber nicht auf&lt;br /&gt;
Filename-Ebene gekapselt — es gibt dafür noch keinen&lt;br /&gt;
Filename-seitigen Aufrufer.&lt;br /&gt;
&lt;br /&gt;
=== Verbindungs-Pooling ===&lt;br /&gt;
&lt;br /&gt;
Alle &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt;-Instanzen, die auf dasselbe Tripel&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; zeigen, teilen sich einen&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; samt einem &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Der Pool ist klassenseitig und wird von einem einzigen&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt; bewacht:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy-Aufbau&#039;&#039;&#039; — TCP + KEX + userauth + SFTP-INIT laufen erst beim ersten SFTP-Aufruf, nicht in &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host&#039;&#039;&#039; — SFTP-Anfragen an einen bestimmten Host werden durch einen &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; mit dem Namen &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; serialisiert (sichtbar im SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle-Verdrängung&#039;&#039;&#039; — ein Pool-Eintrag, der länger als&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt; ungenutzt liegt, wird beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet.&lt;br /&gt;
* &#039;&#039;&#039;Automatischer Reconnect&#039;&#039;&#039; — ein Fehler auf Transportebene (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den Pool-Eintrag, öffnet einen frischen Client und wiederholt die Anfrage &#039;&#039;&#039;einmal&#039;&#039;&#039;.  Anwendungsfehler aus SFTP-STATUS-Antworten werden sofort durchgereicht.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
&lt;br /&gt;
Geplant, aber noch nicht umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-Channel-Parallelität pro Host&#039;&#039;&#039; — aktuell bedeutet eine TCP- plus eine SFTP-Verbindung pro Host, dass N gleichzeitige Anfragen serialisieren.  Pipelining über mehrere SshClients im Pool (bevorzugt) oder ein transport-seitiger Reader-Prozess, der eingehende Pakete in Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel erlauben, weiter aufzulisten, während das Inhalts-Panel eine große Datei liest.&lt;br /&gt;
* &#039;&#039;&#039;Genaues &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen kann.&lt;br /&gt;
* &#039;&#039;&#039;SFTP-v5/v6-Aushandlung&#039;&#039;&#039; für erweiterte Attribute und FTP-artige Kanonisierung.  (Atomares Überschreibungs-rename ist bereits über die OpenSSH-Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; abgedeckt; siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]].)&lt;br /&gt;
&lt;br /&gt;
= Kommando-Shell =&lt;br /&gt;
&lt;br /&gt;
Lokale Kommando-Shell auf dieser expecco-Maschine.  Typische&lt;br /&gt;
Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm,&lt;br /&gt;
Brücke zwischen entferntem Workflow und lokalem Tool.&lt;br /&gt;
&lt;br /&gt;
Das RemoteAccess-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des&lt;br /&gt;
expecco-Prozesses.  Ausgaben gehen in das expecco-Log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warnung]] &#039;&#039;&#039;Telnet ist ein veraltetes&lt;br /&gt;
Protokoll ohne Verschlüsselung.&#039;&#039;&#039; Passwörter werden im Klartext&lt;br /&gt;
über die Leitung übertragen; jeder im Netzpfad kann sie lesen.&lt;br /&gt;
Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative&lt;br /&gt;
bietet (typisch: alte Industriesteuerungen, Laborgeräte,&lt;br /&gt;
eingebettete Messgeräte ohne SSH-Stack).  Für alles andere&lt;br /&gt;
[[#SSH und SFTP]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Das expecco-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (interne Demo)&lt;br /&gt;
&lt;br /&gt;
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler&lt;br /&gt;
8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für&lt;br /&gt;
Terminal-Optionen.  Verbindungsaufbau zum Ziel-Host:Port; nach&lt;br /&gt;
optionalem In-Band-Login können beide Seiten Daten senden.&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY, Agent-Weiterleitung, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks.&lt;br /&gt;
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack als HTTPS-Transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Netz]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31319</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31319"/>
		<updated>2026-05-26T18:50:31Z</updated>

		<summary type="html">&lt;p&gt;Sv: Document the Automatic Refresh dropdown toggle and its root-type default&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on OpenSSL or libssh.  Use this for anything that touches credentials or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine. Used for local-tool integration and for the local end of a remote workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No encryption, passwords on the wire in clear.  Use only when the target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
&amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt; subclass that lets the rest of ST/X treat a remote SFTP path the same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Refresh&#039;&#039;&#039; button in the toolbar (the round-arrow icon&lt;br /&gt;
between &#039;&#039;Forward&#039;&#039; and &#039;&#039;DirectoryUp&#039;&#039;) re-reads both the&lt;br /&gt;
directory tree and the contents pane on demand.  Works uniformly&lt;br /&gt;
for local and SFTP paths; for SFTP it also flushes the per-file&lt;br /&gt;
STAT cache, so changes made directly on the remote side become&lt;br /&gt;
visible immediately rather than waiting for the 5-second cache TTL&lt;br /&gt;
to expire.&lt;br /&gt;
&lt;br /&gt;
The small arrow next to the Refresh icon opens a dropdown with a&lt;br /&gt;
single checkbox, &#039;&#039;&#039;Automatic Refresh&#039;&#039;&#039;, controlling the&lt;br /&gt;
background polling task that walks every expanded tree item to&lt;br /&gt;
detect external changes.  The default depends on the current root:&lt;br /&gt;
&lt;br /&gt;
* Local filesystem &amp;amp;rarr; &#039;&#039;&#039;on&#039;&#039;&#039; (10-second cycle, matches the&lt;br /&gt;
  long-standing behaviour).&lt;br /&gt;
* SFTP &amp;amp;rarr; &#039;&#039;&#039;off&#039;&#039;&#039;.  Each cycle costs one STAT round-trip&lt;br /&gt;
  per child, which is fine for a handful of local directories but&lt;br /&gt;
  painful over the network.  Click Refresh manually when you need&lt;br /&gt;
  to pick up remote changes.&lt;br /&gt;
&lt;br /&gt;
When you navigate between local and SFTP roots the toggle flips&lt;br /&gt;
automatically &amp;amp;mdash; but only if you haven&#039;t overridden it for&lt;br /&gt;
the previous root.  An explicit user choice is preserved across&lt;br /&gt;
navigations.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of the filesystem holding the currently displayed directory.  Works uniformly for local paths and SFTP paths; for SFTP it requires the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; extension (every modern OpenSSH does).  Sizes are reported in IEC binary units (MiB, GiB, TiB) — the largest unit yielding a value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039; rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
&amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only; gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file unencrypted (agent-only mode ignores the passphrase, since the OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to &#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally; a ST/X on the Windows side does not.  Bridging needs a helper like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s walkback plus each waiter&#039;s, formatted as plain text.  Use when a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed (e.g. legacy PEM, encrypted-without-agent) — the file is skipped, others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime), no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
[[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every modern OpenSSH does), overwrite is atomic; on the rare server that does not, the receiver is emulated as delete-then-rename and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost three round-trips per directory icon, which made the original tree expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link. Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
&#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer to disk on an open handle.  Available on the low-level&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe, EOF, MNU on nil socket) evicts the dead pool entry, opens a fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP + one SFTP channel per host means N concurrent requests serialise.  Pipelining over multiple SshClients in the pool (preferred), or a transport-level reader process demultiplexing to per-channel inboxes, would let the tree pane keep listing while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (first batch only) + CLOSE — three RTTs per probe; needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style canonicalisation.  (Atomic-overwrite rename is already handled via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension; see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31318</id>
		<title>Remote Access</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31318"/>
		<updated>2026-05-26T18:50:28Z</updated>

		<summary type="html">&lt;p&gt;Sv: Document the Automatic Refresh dropdown toggle and its root-type default&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fernzugriff&#039;&#039;&#039; bezeichnet die Möglichkeit, einen entfernten&lt;br /&gt;
Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus&lt;br /&gt;
zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu&lt;br /&gt;
verschieben oder ein Testgerät anzusteuern.  Drei Protokoll-Familien&lt;br /&gt;
sind unterstützt, in absteigender Empfehlungsreihenfolge:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH und SFTP&#039;&#039;&#039; (empfohlen) — verschlüsselte Shell und sichere Dateiübertragung über einen SSH-2-Tunnel.  Reine Smalltalk-Implementierung in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; keine externe Abhängigkeit von OpenSSL oder libssh.  Für alles mit Zugangsdaten oder sensiblen Nutzdaten.&lt;br /&gt;
* &#039;&#039;&#039;Lokale Kommando-Shell&#039;&#039;&#039; — fork + exec auf der lokalen Maschine.  Für die Anbindung lokaler Werkzeuge und für die lokale Seite eines hybriden Workflows.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (veraltet) — Klartext-Terminalsitzung.  Keine Verschlüsselung, Passwörter im Klartext auf der Leitung.  Nur einsetzen, wenn die Gegenstelle keine Alternative bietet.&lt;br /&gt;
&lt;br /&gt;
= SSH und SFTP =&lt;br /&gt;
&lt;br /&gt;
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab&lt;br /&gt;
(RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der&lt;br /&gt;
chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das&lt;br /&gt;
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02).  Zwei Schichten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatischer SSH-Zugriff (entferntes &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY-Shell, Agent-Weiterleitung, ProxyJump-Bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — eine&lt;br /&gt;
&amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;-Unterklasse, die es dem restlichen ST/X&lt;br /&gt;
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale&lt;br /&gt;
Datei.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut:&lt;br /&gt;
zuerst das, was der Anwender sieht und tut, darunter die&lt;br /&gt;
expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails&lt;br /&gt;
für Interessierte.&lt;br /&gt;
&lt;br /&gt;
== Aus dem FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Im Adress-Dropdown eine &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt;-URL einfügen.  Der&lt;br /&gt;
Browser-Tab füllt sich wie bei einem lokalen Pfad.&lt;br /&gt;
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),&lt;br /&gt;
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich&lt;br /&gt;
normal.  Der erste Klick auf einen Host dauert ~200–500 ms&lt;br /&gt;
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte&lt;br /&gt;
Verbindung weiter.&lt;br /&gt;
&lt;br /&gt;
URL-Syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlt &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;, wird der lokale Login-Name verwendet, Port&lt;br /&gt;
ist standardmäßig 22, Pfad standardmäßig &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Die Schaltfläche &#039;&#039;&#039;Refresh&#039;&#039;&#039; in der Symbolleiste&lt;br /&gt;
(Pfeil-Kreis-Symbol zwischen &#039;&#039;Forward&#039;&#039; und &#039;&#039;DirectoryUp&#039;&#039;) liest&lt;br /&gt;
Baum und Inhalts-Panel auf Anforderung neu ein.  Funktioniert&lt;br /&gt;
einheitlich für lokale und SFTP-Pfade; bei SFTP wird zusätzlich der&lt;br /&gt;
per-Datei-STAT-Cache geleert, sodass Änderungen, die direkt auf&lt;br /&gt;
der Gegenseite gemacht wurden, sofort sichtbar werden — ohne auf&lt;br /&gt;
den Ablauf der 5-Sekunden-Cache-TTL zu warten.&lt;br /&gt;
&lt;br /&gt;
Der kleine Pfeil neben dem Refresh-Symbol öffnet ein Aufklappmenü&lt;br /&gt;
mit einem einzelnen Kontrollkästchen, &#039;&#039;&#039;Automatic Refresh&#039;&#039;&#039;, das&lt;br /&gt;
den Hintergrund-Task an- bzw. abschaltet, der alle expandierten&lt;br /&gt;
Baumeinträge auf externe Änderungen prüft.  Die Vorgabe richtet&lt;br /&gt;
sich nach der aktuellen Wurzel:&lt;br /&gt;
&lt;br /&gt;
* Lokales Dateisystem &amp;amp;rarr; &#039;&#039;&#039;an&#039;&#039;&#039; (10-Sekunden-Zyklus,&lt;br /&gt;
  entspricht dem bisherigen Verhalten).&lt;br /&gt;
* SFTP &amp;amp;rarr; &#039;&#039;&#039;aus&#039;&#039;&#039;.  Jeder Zyklus kostet einen&lt;br /&gt;
  STAT-Roundtrip pro Kind — für eine Handvoll lokaler&lt;br /&gt;
  Verzeichnisse harmlos, über das Netz schmerzhaft.  Bei Bedarf&lt;br /&gt;
  manuell auf Refresh klicken, um Änderungen zu sehen.&lt;br /&gt;
&lt;br /&gt;
Beim Wechsel zwischen lokalen und SFTP-Wurzeln wird der Schalter&lt;br /&gt;
automatisch umgelegt &amp;amp;mdash; aber nur, sofern man ihn für die&lt;br /&gt;
vorherige Wurzel nicht selbst verstellt hat.  Eine explizite&lt;br /&gt;
Benutzerwahl bleibt über Navigationen hinweg erhalten.&lt;br /&gt;
&lt;br /&gt;
Das Menü &#039;&#039;&#039;Tools&#039;&#039;&#039; im FileBrowserV2 bietet vier Aktionen — die&lt;br /&gt;
drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek&lt;br /&gt;
sichtbar:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — öffnet den Schlüsselerzeugungs-Dialog, siehe [[#Einen SSH-Schlüssel erzeugen]] unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — öffnet ein interaktives VT100-Terminal zu einem entfernten Host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — navigiert diesen Browser-Tab über SFTP auf ein entferntes Dateisystem.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — zeigt Größe, freien Platz und Belegung des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP setzt der Aufruf voraus, daß der Server die Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; ankündigt (jedes moderne OpenSSH&lt;br /&gt;
tut das).  Größen werden in IEC-Binäreinheiten ausgegeben (MiB,&lt;br /&gt;
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1&lt;br /&gt;
liefert, damit ein TB-großes Volume als &#039;&#039;X TiB&#039;&#039; statt&lt;br /&gt;
&#039;&#039;10240 GiB&#039;&#039; erscheint.&lt;br /&gt;
&lt;br /&gt;
== Aus expecco-Aktionen ==&lt;br /&gt;
&lt;br /&gt;
Das Expecco-RemoteAccess-Plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) stellt folgende Testaktionen&lt;br /&gt;
in der expecco-Aktionspalette bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — öffnet eine SSH-Sitzung über das plattformeigene &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;-Binary (PuTTYs &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; unter Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.&lt;br /&gt;
&lt;br /&gt;
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater&lt;br /&gt;
Schlüssel auf dieser Maschine, öffentlicher Teil in der&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des Zielhosts).  Schlüssel&lt;br /&gt;
erzeugen entweder über den Dialog unten oder über&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Plugin fügt zusätzlich eine Settings-Seite hinzu:&lt;br /&gt;
&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039; mit&lt;br /&gt;
einer einzelnen Schaltfläche &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039;, die&lt;br /&gt;
denselben Dialog öffnet.&lt;br /&gt;
&lt;br /&gt;
== Einen SSH-Schlüssel erzeugen ==&lt;br /&gt;
&lt;br /&gt;
=== Der Dialog (FileBrowserV2 / Settings-Seite) ===&lt;br /&gt;
&lt;br /&gt;
Der Dialog fragt alle Parameter in einem Formular ab:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — wird in den erzeugten Schlüssel eingebettet (Voreinstellung &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — schreibt&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (oder wohin man will) samt&lt;br /&gt;
zugehöriger &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;-Datei daneben.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — schreibt die Datei UND übergibt den Schlüssel dem laufenden ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — der Schlüssel lebt nur im Speicher des Agents; nach Agent-Neustart ist er verloren.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — vollständiger Pfad; ausgegraut im Agent-only-Modus.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — leer lässt die On-Disk-Datei unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten Schlüssel transportiert).&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;Generate&#039;&#039;&#039; wird die Public-Key-Zeile (dieselbe&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt;-Zeichenfolge, die&lt;br /&gt;
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum&lt;br /&gt;
direkten Einfügen in die &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des&lt;br /&gt;
Zielhosts.&lt;br /&gt;
&lt;br /&gt;
=== Aus einem Workspace ===&lt;br /&gt;
&lt;br /&gt;
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; einen reinen Smalltalk-Schlüsselgenerator&lt;br /&gt;
bereit, dessen Ausgabe bit-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt; ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Passphrase-verschlüsselt auf Platte speichern&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ UND in den laufenden Agent laden&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll&lt;br /&gt;
interoperabel (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; rekonstruiert den&lt;br /&gt;
öffentlichen Schlüssel, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; ändert&lt;br /&gt;
die Passphrase usw.).&lt;br /&gt;
&lt;br /&gt;
=== Mit den Shell-Werkzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der klassische Weg funktioniert weiterhin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ssh-agent vorbereiten ==&lt;br /&gt;
&lt;br /&gt;
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien&lt;br /&gt;
deutlich vorzuziehen: er hält verschlüsselte private Schlüssel&lt;br /&gt;
einmal pro Sitzung entsperrt und kann Identitäten verwalten&lt;br /&gt;
(hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X&lt;br /&gt;
nie direkt sehen soll.&lt;br /&gt;
&lt;br /&gt;
ST/X erkennt den Agent-Pfad automatisch, sobald&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;zum Zeitpunkt des Starts von stx&#039;&#039;&#039;&lt;br /&gt;
in der Prozessumgebung gesetzt ist.  Eine spätere Zuweisung aus&lt;br /&gt;
einem Workspace nützt nichts.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Die meisten Desktop-Distributionen starten einen Agent automatisch&lt;br /&gt;
beim Login (gnome-keyring unter GNOME, ssh-agent.service unter&lt;br /&gt;
systemd, KWallet unter KDE).  Prüfen im Terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh oder ähnlich&lt;br /&gt;
ssh-add -l             # listet geladene Identitäten&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # eigene laden, falls nicht da&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei&lt;br /&gt;
aufnehmen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc oder ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X muss aus einer Shell gestartet werden, die diese rc bereits&lt;br /&gt;
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die&lt;br /&gt;
Variable nicht.  Empfehlung: ein kleines Wrapper-Skript unter&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt;, das die rc sourcet und dann stx&lt;br /&gt;
startet.&lt;br /&gt;
&lt;br /&gt;
Die Settings-Seite (&#039;&#039;&#039;Extras → Settings → Plugins → Remote&lt;br /&gt;
Access — SSH Keys&#039;&#039;&#039;) zeigt an, ob das laufende Image einen&lt;br /&gt;
Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Permanente Einrichtung via systemd ====&lt;br /&gt;
&lt;br /&gt;
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-&lt;br /&gt;
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den&lt;br /&gt;
meisten Distros mit dem Paket &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
ausgelieferte Per-User-systemd-Unit aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; in der Shell-rc auf den&lt;br /&gt;
User-Service-Socket zeigen lassen (ersetzt das&lt;br /&gt;
&amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;-Snippet oben):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Um den manuellen &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt;-Schritt zu sparen, kann&lt;br /&gt;
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.&lt;br /&gt;
In &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt; eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und&lt;br /&gt;
übergibt den entsperrten Schlüssel an den Agent; weitere&lt;br /&gt;
Verbindungen nutzen die gespeicherte Identität ohne Prompt.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit.&lt;br /&gt;
Einmalige Einrichtung:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Dienste&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) als Administrator öffnen.&lt;br /&gt;
# &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039; suchen, Starttyp auf &#039;&#039;&#039;Automatisch&#039;&#039;&#039; setzen, &#039;&#039;&#039;Starten&#039;&#039;&#039; anklicken.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Prüfen: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), nicht auf einem&lt;br /&gt;
Unix-Socket.  ST/X unterstützt beide Transporte, jedoch setzt das&lt;br /&gt;
Windows-ssh-add &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; selbst.&lt;br /&gt;
Daher einmalig systemweit setzen:&lt;br /&gt;
&lt;br /&gt;
# {{Key|Win}} drücken → &amp;quot;Umgebungsvariablen&amp;quot; → „Systemumgebungs- variablen bearbeiten&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Umgebungsvariablen&#039;&#039;&#039; → unter &#039;&#039;&#039;Benutzervariablen&#039;&#039;&#039;, &#039;&#039;&#039;Neu&#039;&#039;&#039; klicken.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Wert: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ab- und wieder anmelden (oder stx neu starten), damit die neue Umgebung übernommen wird.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell-Schnelleinrichtung ====&lt;br /&gt;
&lt;br /&gt;
Derselbe Aufbau aus einer &#039;&#039;&#039;Administrator-PowerShell&#039;&#039;&#039; heraus,&lt;br /&gt;
z.B. für Skripte oder unbeaufsichtigte Bereitstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Agent jetzt und bei jedem Neustart starten (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung&lt;br /&gt;
(z.B. Einzelsitzung) die &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt;-Zeile weglassen&lt;br /&gt;
und nur &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt; ausführen.  Die&lt;br /&gt;
env-var-Zeile lässt sich ebenfalls weglassen, wenn&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; nur in der aktuellen Shell gebraucht&lt;br /&gt;
wird — dann statt der &amp;lt;code&amp;gt;[Environment]&amp;lt;/code&amp;gt;-Variante&lt;br /&gt;
&amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Auf stark abgespeckten Windows-Installationen ist der&lt;br /&gt;
ssh-agent-Dienst eventuell nicht vorhanden.  Einmalig nachrüsten&lt;br /&gt;
über &#039;&#039;&#039;Einstellungen → Apps → Optionale Features → OpenSSH-&lt;br /&gt;
Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative Agenten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — eigenes Protokoll; von ST/X&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Agent&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; unterstützt.  Schlüssel zu&lt;br /&gt;
OpenSSH migrieren.&lt;br /&gt;
* &#039;&#039;&#039;Git für Windows ssh-agent&#039;&#039;&#039; — funktioniert;&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; auf den dort veröffentlichten Socket&lt;br /&gt;
zeigen lassen.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — ein ST/X innerhalb der WSL sieht den WSL-eigenen Agent normal; ein ST/X auf der Windows-Seite nicht.  Eine Brücke per &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt; ist möglich.&lt;br /&gt;
&lt;br /&gt;
Prüfung über die Settings-Seite&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
die Anzeige dort meldet, ob das laufende Image den Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Windows-OpenSSH speichert agent-geladene Schlüssel &#039;&#039;&#039;nicht&#039;&#039;&#039;&lt;br /&gt;
über Agent-Neustarts hinweg.  Um nicht nach jedem Reboot manuell&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; aufrufen zu müssen, dieselbe Lazy-Load-&lt;br /&gt;
Konfiguration in &amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;&lt;br /&gt;
eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent&lt;br /&gt;
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige&lt;br /&gt;
Sitzung weiter.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Alle Stellschrauben sind klassenseitig auf&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; erreichbar:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Voreinstellung !! Steuert&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 Min) || Wie lange&lt;br /&gt;
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.&lt;br /&gt;
Liegt knapp unter dem typischen&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; des sshd,&lt;br /&gt;
damit wir uns recyceln, bevor der Server uns mit TCP-RESET&lt;br /&gt;
trennt.  &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; setzt auf Voreinstellung zurück.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Maximales Alter (s)&lt;br /&gt;
eines gecachten STAT, bevor &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; neu am&lt;br /&gt;
Server fragt.  Eltern-listDir stempelt ohnehin frische Attribute&lt;br /&gt;
auf alle Kinder, daher zahlt das Navigieren im offenen&lt;br /&gt;
Verzeichnis das TTL nicht.  &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; schaltet den Cache&lt;br /&gt;
ab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (Aktion) || Reißt jede&lt;br /&gt;
gepoolte Verbindung ab.  Nützlich nach einem bekannt schlechten&lt;br /&gt;
Netzereignis, vor einem bewussten Identitätswechsel oder zum&lt;br /&gt;
sauberen Image-Shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnose ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; über das Untermenü „Status&amp;quot; des&lt;br /&gt;
Launchers öffnen.  Der pro-Host-SFTP-Mutex erscheint als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;, der pool-weite Mutex als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Per Rechtsklick:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — schreibt den Walkback des letzten Eigners samt aller Waiter als Text in die Zwischenablage.  Unverzichtbar, wenn ein Prozess in&lt;br /&gt;
&amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; innerhalb von&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; klemmt.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — die ganze Tabelle, ideal für eine E-Mail-Diagnose.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS über den Wait-for-Graph, meldet Zyklen.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
Interessante Ereignisse werden über &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; geloggt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei automatischem Reconnect nach toter Verbindung.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei Idle-Verdrängung eines Pool-Eintrags.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; wenn eine SSH-Schlüsseldatei nicht geparst werden konnte — die Datei wird übersprungen.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nur SFTP v3.&#039;&#039;&#039;  Kein SETSTAT (kein entferntes chmod / chown / utime), kein SSH_FXP_READLINK exponiert (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; liefert immer &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; die normale stat-Info).  Einige&lt;br /&gt;
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische&lt;br /&gt;
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host.&#039;&#039;&#039;  Zwei gleichzeitige Operationen am selben Host stehen am Host-Mutex an.  Siehe [[#Ausblick]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt;-Fallback hat ein TOCTOU-Fenster.&#039;&#039;&#039; Bei Servern, die &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; ankündigen (jedes moderne OpenSSH tut das), ist das Überschreiben atomar. Beim seltenen Server, der das nicht tut, wird auf Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich dazwischenschieben.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; ist eine Heuristik.&#039;&#039;&#039; Liefert immer &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (die genaue Antwort würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).&lt;br /&gt;
&lt;br /&gt;
== Implementierungsdetails ==&lt;br /&gt;
&lt;br /&gt;
Für Leser, die die Architektur verstehen wollen.  Fünf Klassen,&lt;br /&gt;
von oben nach unten:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Aufgabe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename-Unterklasse, die&lt;br /&gt;
öffentliche API.  Bildet &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt;-URLs auf&lt;br /&gt;
entfernte Dateien ab und stellt &amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; usw. bereit.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3-Protokoll&lt;br /&gt;
(Request/Response-Codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Wird von SftpFilename angesteuert.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH-Kanal-Multiplexer (CHANNEL_OPEN,&lt;br /&gt;
DATA, EOF, CLOSE, WINDOW_ADJUST).  Eine logische Sitzung pro&lt;br /&gt;
Channel-Instanz.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-Level-SSH-Client: öffnet den&lt;br /&gt;
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und&lt;br /&gt;
verteilt anschließend Kanäle.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Drahtschicht.  Banner- und&lt;br /&gt;
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq /&lt;br /&gt;
recvSeq, Heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH-SFTP-Erweiterungen ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst&lt;br /&gt;
minimal gehalten.  OpenSSH bringt einen offenen&lt;br /&gt;
Erweiterungsmechanismus mit: der Server listet im&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;-Reply die Erweiterungsnamen auf, die&lt;br /&gt;
er versteht, und der Client ruft sie über&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt;-Pakete mit dem&lt;br /&gt;
Erweiterungsnamen als erstem String auf.  Jede Erweiterung wird&lt;br /&gt;
über &amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;&lt;br /&gt;
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie&lt;br /&gt;
nicht ankündigt.&lt;br /&gt;
&lt;br /&gt;
Der Stack nutzt heute vier OpenSSH-Erweiterungen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomares rename-mit-Überschreiben.  Wird automatisch von&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt; aufgegriffen; die&lt;br /&gt;
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum&lt;br /&gt;
Einsatz, die die Erweiterung nicht haben.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — Erzeugt einen POSIX-Hardlink. Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX-&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-typische Dateisystem-Statistik.&lt;br /&gt;
Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;;&lt;br /&gt;
das Ergebnis ist form-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;, sodass Aufrufer&lt;br /&gt;
lokale und entfernte Pfade einheitlich behandeln können.&lt;br /&gt;
Treibt den Menü-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; an,&lt;br /&gt;
der am Anfang dieser Seite beschrieben ist.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — schreibt den serverseitigen Schreibpuffer eines geöffneten Handles auf Platte.  Liegt als&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt; bereit; noch nicht&lt;br /&gt;
in eine &amp;quot;Durable-Write&amp;quot;-API auf Filename-Ebene eingebunden.&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden OpenSSH-Erweiterungen&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
werden in der angekündigten Liste erkannt, aber nicht auf&lt;br /&gt;
Filename-Ebene gekapselt — es gibt dafür noch keinen&lt;br /&gt;
Filename-seitigen Aufrufer.&lt;br /&gt;
&lt;br /&gt;
=== Verbindungs-Pooling ===&lt;br /&gt;
&lt;br /&gt;
Alle &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt;-Instanzen, die auf dasselbe Tripel&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; zeigen, teilen sich einen&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; samt einem &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Der Pool ist klassenseitig und wird von einem einzigen&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt; bewacht:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy-Aufbau&#039;&#039;&#039; — TCP + KEX + userauth + SFTP-INIT laufen erst beim ersten SFTP-Aufruf, nicht in &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host&#039;&#039;&#039; — SFTP-Anfragen an einen bestimmten Host werden durch einen &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; mit dem Namen &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; serialisiert (sichtbar im SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle-Verdrängung&#039;&#039;&#039; — ein Pool-Eintrag, der länger als&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt; ungenutzt liegt, wird beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet.&lt;br /&gt;
* &#039;&#039;&#039;Automatischer Reconnect&#039;&#039;&#039; — ein Fehler auf Transportebene (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den Pool-Eintrag, öffnet einen frischen Client und wiederholt die Anfrage &#039;&#039;&#039;einmal&#039;&#039;&#039;.  Anwendungsfehler aus SFTP-STATUS-Antworten werden sofort durchgereicht.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
&lt;br /&gt;
Geplant, aber noch nicht umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-Channel-Parallelität pro Host&#039;&#039;&#039; — aktuell bedeutet eine TCP- plus eine SFTP-Verbindung pro Host, dass N gleichzeitige Anfragen serialisieren.  Pipelining über mehrere SshClients im Pool (bevorzugt) oder ein transport-seitiger Reader-Prozess, der eingehende Pakete in Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel erlauben, weiter aufzulisten, während das Inhalts-Panel eine große Datei liest.&lt;br /&gt;
* &#039;&#039;&#039;Genaues &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen kann.&lt;br /&gt;
* &#039;&#039;&#039;SFTP-v5/v6-Aushandlung&#039;&#039;&#039; für erweiterte Attribute und FTP-artige Kanonisierung.  (Atomares Überschreibungs-rename ist bereits über die OpenSSH-Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; abgedeckt; siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]].)&lt;br /&gt;
&lt;br /&gt;
= Kommando-Shell =&lt;br /&gt;
&lt;br /&gt;
Lokale Kommando-Shell auf dieser expecco-Maschine.  Typische&lt;br /&gt;
Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm,&lt;br /&gt;
Brücke zwischen entferntem Workflow und lokalem Tool.&lt;br /&gt;
&lt;br /&gt;
Das RemoteAccess-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des&lt;br /&gt;
expecco-Prozesses.  Ausgaben gehen in das expecco-Log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warnung]] &#039;&#039;&#039;Telnet ist ein veraltetes&lt;br /&gt;
Protokoll ohne Verschlüsselung.&#039;&#039;&#039; Passwörter werden im Klartext&lt;br /&gt;
über die Leitung übertragen; jeder im Netzpfad kann sie lesen.&lt;br /&gt;
Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative&lt;br /&gt;
bietet (typisch: alte Industriesteuerungen, Laborgeräte,&lt;br /&gt;
eingebettete Messgeräte ohne SSH-Stack).  Für alles andere&lt;br /&gt;
[[#SSH und SFTP]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Das expecco-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (interne Demo)&lt;br /&gt;
&lt;br /&gt;
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler&lt;br /&gt;
8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für&lt;br /&gt;
Terminal-Optionen.  Verbindungsaufbau zum Ziel-Host:Port; nach&lt;br /&gt;
optionalem In-Band-Login können beide Seiten Daten senden.&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY, Agent-Weiterleitung, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks.&lt;br /&gt;
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack als HTTPS-Transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Netz]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31306</id>
		<title>Release Notes 26.x</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Release_Notes_26.x&amp;diff=31306"/>
		<updated>2026-05-26T14:42:30Z</updated>

		<summary type="html">&lt;p&gt;Sv: update bridge features: SSL for all bridges incl. Dart+Smalltalk, getFile/putFile/makeDirectory for all bridges, defineFunction/callFunction for NodeJS/Ruby/Smalltalk&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;See also: [[Release Notes 25.x]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Release 26.2 (Q4 2026) ==&lt;br /&gt;
&lt;br /&gt;
== Release 26.1 (Q2 2026) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Feature: &#039;&#039;&#039;NEW&#039;&#039;&#039; [[KI Coding Plugin|&#039;&#039;&#039;AI Coding&#039;&#039;&#039;]] plugin (chat-assistant integration for the activity editor and class browser):&lt;br /&gt;
** supports both &#039;&#039;&#039;Anthropic Claude&#039;&#039;&#039;, &#039;&#039;&#039;OpenAI ChatGPT&#039;&#039;&#039; or &#039;&#039;&#039;Llama&#039;&#039;&#039; as backends, switchable from the settings dialog (Plugins → AI Coding);&amp;lt;br&amp;gt;API keys are stored per provider so you can flip between them without re-entering&lt;br /&gt;
** Toolbar / class-browser menu adapts to the active provider — reads &amp;quot;&#039;&#039;Ask Claude&#039;&#039;&amp;quot; or &amp;quot;&#039;&#039;Ask ChatGPT&#039;&#039;&amp;quot;, updates live when the provider is switched&lt;br /&gt;
** Menu actions: Explain code/method, Suggest improvement, Generate test, Generate doc-comment (fills the Documentation tab and pin comments), Find bugs, Custom prompt; &amp;quot;[Apply]&amp;quot; can install proposed code directly into the activity body or compile a proposed helper method into a class&lt;br /&gt;
** Chat window streams responses live (Server-Sent Events) and shows running token count + estimated cost in the title; supports image attachments (screenshots / PNG-JPG files)&lt;br /&gt;
** model, API key, endpoint and max-tokens are configurable via the Claude settings dialog&lt;br /&gt;
* Feature: SSL1.3 support (without external SSL library)&lt;br /&gt;
* Feature: SSL support for C, Python, NodeJS, Ruby, Dart and Smalltalk bridges (combined cert+key PEM files supported)&lt;br /&gt;
* Feature: SSH builtin, plus SSH and SFTP clients (both via FileBrowser)&lt;br /&gt;
* Feature: public/private keypair generation via a FileBrowser menu (for easy SSH setup)&lt;br /&gt;
* Feature: Qt-Plugin supports Qt6.8 ([[QT_Testing/en#ExpeccoTestService_Library%3A_Delivery_in_Expecco_Versions|Delivered versions for QT and build environment]])&lt;br /&gt;
* Feature: improved search text box behavior in text editors (type RETURN, CMD-f or CMD-b while box is open) and back to original position button added.&lt;br /&gt;
* Feature: Improved/Fixed Number stack:&lt;br /&gt;
** Enhanced multiprecision numbers (eg. &amp;lt;float&amp;gt;q, &amp;lt;float&amp;gt;Q constants in freeze values)&lt;br /&gt;
** Float32 numbers (&amp;lt;float&amp;gt;f)&lt;br /&gt;
** Integer freezeValues in exponential notation (eg. 1e5)&lt;br /&gt;
** Recognize type specific infinities eg. &amp;quot;inf.0&amp;quot;, &amp;quot;inf.0f&amp;quot;, &amp;quot;inf.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** Recognize type specific NaNs eg. &amp;quot;nan.0&amp;quot;, &amp;quot;nan.0f&amp;quot;, &amp;quot;nan.0q&amp;quot; etc. (useful when parsing/receiving values from the outside world)&lt;br /&gt;
** fixed/added missing trigonometric functions for multiprecision floats and complex numbers (eg. arcTan)&lt;br /&gt;
** inspector (and activitylog as a consequence) show the type of a float (suffix &#039;f&#039;, &#039;q&#039;, &#039;Q&#039; etc.)&lt;br /&gt;
&lt;br /&gt;
* Feature: Workflow editor — improved orthogonal routing of connections:&lt;br /&gt;
** connections now detour around blocks, freeze values and annotation boxes instead of cutting through them&lt;br /&gt;
** connections from a compound block&#039;s input-pin descriptions are bundled into a bus column next to the source pin&lt;br /&gt;
** end-stub avoidance no longer fires on near-misses (strict overlap check, no clearance margin)&lt;br /&gt;
** routing prefers the source-side bend when the source step has multiple sibling pins&lt;br /&gt;
* Feature: Workflow editor — improved naïve autolayout: added horizontal and vertical expansion passes that spread adjacent blocks apart for clearer connection routing&lt;br /&gt;
* Feature: file transfer (getFile/putFile) and makeDirectory for all bridges (C, Python, NodeJS, Ruby, Dart, Smalltalk)&lt;br /&gt;
* Feature: defineFunction/callFunction support for NodeJS, Ruby and Smalltalk bridges&lt;br /&gt;
* Performance: execution of elementary Smalltalk and JavaScript actions tuned for speed (Jitter improvements)&lt;br /&gt;
* Feature: OLE for 64 bit architectures&lt;br /&gt;
* Feature: optional HTTPS for the AIDYMO and license server — drop a PEM cert+key into &amp;lt;code&amp;gt;--workDir&amp;lt;/code&amp;gt; (combined &amp;lt;code&amp;gt;server.pem&amp;lt;/code&amp;gt;, or split&amp;lt;code&amp;gt;fullchain.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;privkey.pem&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;cert.pem&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;key.pem&amp;lt;/code&amp;gt;) and the service binds TLS automatically; informational hostname is derived from the certificate (SAN-aware, wildcard- and multi-SAN-safe)&lt;br /&gt;
* Feature: more search options in the [[How_to_Program/en#MethodFinder:_Find_Functions_by_Example | MethodFinder]]. &lt;br /&gt;
*Fix: many fixes related to DPI scaling. I.e. when multiple monitors are configured with different scaling (especially different from 100%). Includes scaling of fonts, bitmap and UI components (widgets).&lt;br /&gt;
*Fix: display of very long lines in a text editor/inspector (workaround a Windows 16bit line limit)&lt;br /&gt;
*Fix: due to a bug in enumeration datatypes, the size of &amp;quot;.ets&amp;quot; files grew over time to huge sizes (some information was redundantly and identically written twice). This had no effect on the execution, but made load/save times almost unacceptably long by storing/reloading unneeded data. When loaded and saved again, this will fix those ets files automatically (there is also a patch for older versions)&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31305</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31305"/>
		<updated>2026-05-26T13:46:08Z</updated>

		<summary type="html">&lt;p&gt;Sv: Document the Refresh toolbar button (and the disabled tree auto-poll)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on OpenSSL or libssh.  Use this for anything that touches credentials or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine. Used for local-tool integration and for the local end of a remote workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No encryption, passwords on the wire in clear.  Use only when the target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
&amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt; subclass that lets the rest of ST/X treat a remote SFTP path the same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The directory tree does &#039;&#039;&#039;not&#039;&#039;&#039; auto-update: previously a background&lt;br /&gt;
task walked every expanded item every 10 seconds, which over SFTP&lt;br /&gt;
meant one STAT round-trip per child on every cycle.  Click the&lt;br /&gt;
&#039;&#039;&#039;Refresh&#039;&#039;&#039; button in the toolbar (the round-arrow icon between&lt;br /&gt;
&#039;&#039;Forward&#039;&#039; and &#039;&#039;DirectoryUp&#039;&#039;) to re-read the tree and the&lt;br /&gt;
contents pane on demand.  Refresh works uniformly for local and&lt;br /&gt;
SFTP paths; for SFTP it also flushes the per-file STAT cache, so&lt;br /&gt;
changes made directly on the remote side become visible&lt;br /&gt;
immediately rather than waiting for the 5-second cache TTL to&lt;br /&gt;
expire.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of the filesystem holding the currently displayed directory.  Works uniformly for local paths and SFTP paths; for SFTP it requires the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; extension (every modern OpenSSH does).  Sizes are reported in IEC binary units (MiB, GiB, TiB) — the largest unit yielding a value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039; rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
&amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only; gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file unencrypted (agent-only mode ignores the passphrase, since the OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to &#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally; a ST/X on the Windows side does not.  Bridging needs a helper like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s walkback plus each waiter&#039;s, formatted as plain text.  Use when a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed (e.g. legacy PEM, encrypted-without-agent) — the file is skipped, others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime), no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
[[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every modern OpenSSH does), overwrite is atomic; on the rare server that does not, the receiver is emulated as delete-then-rename and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost three round-trips per directory icon, which made the original tree expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link. Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
&#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer to disk on an open handle.  Available on the low-level&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe, EOF, MNU on nil socket) evicts the dead pool entry, opens a fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP + one SFTP channel per host means N concurrent requests serialise.  Pipelining over multiple SshClients in the pool (preferred), or a transport-level reader process demultiplexing to per-channel inboxes, would let the tree pane keep listing while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (first batch only) + CLOSE — three RTTs per probe; needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style canonicalisation.  (Atomic-overwrite rename is already handled via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension; see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31304</id>
		<title>Remote Access</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31304"/>
		<updated>2026-05-26T13:46:07Z</updated>

		<summary type="html">&lt;p&gt;Sv: Document the Refresh toolbar button (and the disabled tree auto-poll)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fernzugriff&#039;&#039;&#039; bezeichnet die Möglichkeit, einen entfernten&lt;br /&gt;
Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus&lt;br /&gt;
zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu&lt;br /&gt;
verschieben oder ein Testgerät anzusteuern.  Drei Protokoll-Familien&lt;br /&gt;
sind unterstützt, in absteigender Empfehlungsreihenfolge:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH und SFTP&#039;&#039;&#039; (empfohlen) — verschlüsselte Shell und sichere Dateiübertragung über einen SSH-2-Tunnel.  Reine Smalltalk-Implementierung in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; keine externe Abhängigkeit von OpenSSL oder libssh.  Für alles mit Zugangsdaten oder sensiblen Nutzdaten.&lt;br /&gt;
* &#039;&#039;&#039;Lokale Kommando-Shell&#039;&#039;&#039; — fork + exec auf der lokalen Maschine.  Für die Anbindung lokaler Werkzeuge und für die lokale Seite eines hybriden Workflows.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (veraltet) — Klartext-Terminalsitzung.  Keine Verschlüsselung, Passwörter im Klartext auf der Leitung.  Nur einsetzen, wenn die Gegenstelle keine Alternative bietet.&lt;br /&gt;
&lt;br /&gt;
= SSH und SFTP =&lt;br /&gt;
&lt;br /&gt;
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab&lt;br /&gt;
(RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der&lt;br /&gt;
chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das&lt;br /&gt;
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02).  Zwei Schichten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatischer SSH-Zugriff (entferntes &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY-Shell, Agent-Weiterleitung, ProxyJump-Bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — eine&lt;br /&gt;
&amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;-Unterklasse, die es dem restlichen ST/X&lt;br /&gt;
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale&lt;br /&gt;
Datei.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut:&lt;br /&gt;
zuerst das, was der Anwender sieht und tut, darunter die&lt;br /&gt;
expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails&lt;br /&gt;
für Interessierte.&lt;br /&gt;
&lt;br /&gt;
== Aus dem FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Im Adress-Dropdown eine &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt;-URL einfügen.  Der&lt;br /&gt;
Browser-Tab füllt sich wie bei einem lokalen Pfad.&lt;br /&gt;
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),&lt;br /&gt;
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich&lt;br /&gt;
normal.  Der erste Klick auf einen Host dauert ~200–500 ms&lt;br /&gt;
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte&lt;br /&gt;
Verbindung weiter.&lt;br /&gt;
&lt;br /&gt;
URL-Syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlt &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;, wird der lokale Login-Name verwendet, Port&lt;br /&gt;
ist standardmäßig 22, Pfad standardmäßig &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Verzeichnisbaum aktualisiert sich &#039;&#039;&#039;nicht&#039;&#039;&#039; automatisch:&lt;br /&gt;
früher lief im Hintergrund alle 10 Sekunden ein Task über jeden&lt;br /&gt;
expandierten Eintrag, was bei SFTP einen STAT-Roundtrip pro Kind&lt;br /&gt;
und Zyklus bedeutete.  Mit der Schaltfläche &#039;&#039;&#039;Refresh&#039;&#039;&#039; in der&lt;br /&gt;
Symbolleiste (Pfeil-Kreis-Symbol zwischen &#039;&#039;Forward&#039;&#039; und&lt;br /&gt;
&#039;&#039;DirectoryUp&#039;&#039;) werden Baum und Inhalts-Panel auf Anforderung&lt;br /&gt;
neu eingelesen.  Refresh funktioniert einheitlich für lokale und&lt;br /&gt;
SFTP-Pfade; bei SFTP wird zusätzlich der per-Datei-STAT-Cache&lt;br /&gt;
geleert, sodass Änderungen, die direkt auf der Gegenseite&lt;br /&gt;
gemacht wurden, sofort sichtbar werden — ohne auf den Ablauf der&lt;br /&gt;
5-Sekunden-Cache-TTL zu warten.&lt;br /&gt;
&lt;br /&gt;
Das Menü &#039;&#039;&#039;Tools&#039;&#039;&#039; im FileBrowserV2 bietet vier Aktionen — die&lt;br /&gt;
drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek&lt;br /&gt;
sichtbar:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — öffnet den Schlüsselerzeugungs-Dialog, siehe [[#Einen SSH-Schlüssel erzeugen]] unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — öffnet ein interaktives VT100-Terminal zu einem entfernten Host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — navigiert diesen Browser-Tab über SFTP auf ein entferntes Dateisystem.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — zeigt Größe, freien Platz und Belegung des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP setzt der Aufruf voraus, daß der Server die Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; ankündigt (jedes moderne OpenSSH&lt;br /&gt;
tut das).  Größen werden in IEC-Binäreinheiten ausgegeben (MiB,&lt;br /&gt;
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1&lt;br /&gt;
liefert, damit ein TB-großes Volume als &#039;&#039;X TiB&#039;&#039; statt&lt;br /&gt;
&#039;&#039;10240 GiB&#039;&#039; erscheint.&lt;br /&gt;
&lt;br /&gt;
== Aus expecco-Aktionen ==&lt;br /&gt;
&lt;br /&gt;
Das Expecco-RemoteAccess-Plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) stellt folgende Testaktionen&lt;br /&gt;
in der expecco-Aktionspalette bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — öffnet eine SSH-Sitzung über das plattformeigene &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;-Binary (PuTTYs &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; unter Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.&lt;br /&gt;
&lt;br /&gt;
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater&lt;br /&gt;
Schlüssel auf dieser Maschine, öffentlicher Teil in der&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des Zielhosts).  Schlüssel&lt;br /&gt;
erzeugen entweder über den Dialog unten oder über&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Plugin fügt zusätzlich eine Settings-Seite hinzu:&lt;br /&gt;
&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039; mit&lt;br /&gt;
einer einzelnen Schaltfläche &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039;, die&lt;br /&gt;
denselben Dialog öffnet.&lt;br /&gt;
&lt;br /&gt;
== Einen SSH-Schlüssel erzeugen ==&lt;br /&gt;
&lt;br /&gt;
=== Der Dialog (FileBrowserV2 / Settings-Seite) ===&lt;br /&gt;
&lt;br /&gt;
Der Dialog fragt alle Parameter in einem Formular ab:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — wird in den erzeugten Schlüssel eingebettet (Voreinstellung &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — schreibt&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (oder wohin man will) samt&lt;br /&gt;
zugehöriger &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;-Datei daneben.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — schreibt die Datei UND übergibt den Schlüssel dem laufenden ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — der Schlüssel lebt nur im Speicher des Agents; nach Agent-Neustart ist er verloren.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — vollständiger Pfad; ausgegraut im Agent-only-Modus.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — leer lässt die On-Disk-Datei unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten Schlüssel transportiert).&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;Generate&#039;&#039;&#039; wird die Public-Key-Zeile (dieselbe&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt;-Zeichenfolge, die&lt;br /&gt;
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum&lt;br /&gt;
direkten Einfügen in die &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des&lt;br /&gt;
Zielhosts.&lt;br /&gt;
&lt;br /&gt;
=== Aus einem Workspace ===&lt;br /&gt;
&lt;br /&gt;
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; einen reinen Smalltalk-Schlüsselgenerator&lt;br /&gt;
bereit, dessen Ausgabe bit-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt; ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Passphrase-verschlüsselt auf Platte speichern&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ UND in den laufenden Agent laden&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll&lt;br /&gt;
interoperabel (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; rekonstruiert den&lt;br /&gt;
öffentlichen Schlüssel, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; ändert&lt;br /&gt;
die Passphrase usw.).&lt;br /&gt;
&lt;br /&gt;
=== Mit den Shell-Werkzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der klassische Weg funktioniert weiterhin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ssh-agent vorbereiten ==&lt;br /&gt;
&lt;br /&gt;
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien&lt;br /&gt;
deutlich vorzuziehen: er hält verschlüsselte private Schlüssel&lt;br /&gt;
einmal pro Sitzung entsperrt und kann Identitäten verwalten&lt;br /&gt;
(hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X&lt;br /&gt;
nie direkt sehen soll.&lt;br /&gt;
&lt;br /&gt;
ST/X erkennt den Agent-Pfad automatisch, sobald&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;zum Zeitpunkt des Starts von stx&#039;&#039;&#039;&lt;br /&gt;
in der Prozessumgebung gesetzt ist.  Eine spätere Zuweisung aus&lt;br /&gt;
einem Workspace nützt nichts.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Die meisten Desktop-Distributionen starten einen Agent automatisch&lt;br /&gt;
beim Login (gnome-keyring unter GNOME, ssh-agent.service unter&lt;br /&gt;
systemd, KWallet unter KDE).  Prüfen im Terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh oder ähnlich&lt;br /&gt;
ssh-add -l             # listet geladene Identitäten&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # eigene laden, falls nicht da&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei&lt;br /&gt;
aufnehmen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc oder ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X muss aus einer Shell gestartet werden, die diese rc bereits&lt;br /&gt;
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die&lt;br /&gt;
Variable nicht.  Empfehlung: ein kleines Wrapper-Skript unter&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt;, das die rc sourcet und dann stx&lt;br /&gt;
startet.&lt;br /&gt;
&lt;br /&gt;
Die Settings-Seite (&#039;&#039;&#039;Extras → Settings → Plugins → Remote&lt;br /&gt;
Access — SSH Keys&#039;&#039;&#039;) zeigt an, ob das laufende Image einen&lt;br /&gt;
Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Permanente Einrichtung via systemd ====&lt;br /&gt;
&lt;br /&gt;
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-&lt;br /&gt;
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den&lt;br /&gt;
meisten Distros mit dem Paket &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
ausgelieferte Per-User-systemd-Unit aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; in der Shell-rc auf den&lt;br /&gt;
User-Service-Socket zeigen lassen (ersetzt das&lt;br /&gt;
&amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;-Snippet oben):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Um den manuellen &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt;-Schritt zu sparen, kann&lt;br /&gt;
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.&lt;br /&gt;
In &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt; eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und&lt;br /&gt;
übergibt den entsperrten Schlüssel an den Agent; weitere&lt;br /&gt;
Verbindungen nutzen die gespeicherte Identität ohne Prompt.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit.&lt;br /&gt;
Einmalige Einrichtung:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Dienste&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) als Administrator öffnen.&lt;br /&gt;
# &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039; suchen, Starttyp auf &#039;&#039;&#039;Automatisch&#039;&#039;&#039; setzen, &#039;&#039;&#039;Starten&#039;&#039;&#039; anklicken.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Prüfen: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), nicht auf einem&lt;br /&gt;
Unix-Socket.  ST/X unterstützt beide Transporte, jedoch setzt das&lt;br /&gt;
Windows-ssh-add &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; selbst.&lt;br /&gt;
Daher einmalig systemweit setzen:&lt;br /&gt;
&lt;br /&gt;
# {{Key|Win}} drücken → &amp;quot;Umgebungsvariablen&amp;quot; → „Systemumgebungs- variablen bearbeiten&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Umgebungsvariablen&#039;&#039;&#039; → unter &#039;&#039;&#039;Benutzervariablen&#039;&#039;&#039;, &#039;&#039;&#039;Neu&#039;&#039;&#039; klicken.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Wert: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ab- und wieder anmelden (oder stx neu starten), damit die neue Umgebung übernommen wird.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell-Schnelleinrichtung ====&lt;br /&gt;
&lt;br /&gt;
Derselbe Aufbau aus einer &#039;&#039;&#039;Administrator-PowerShell&#039;&#039;&#039; heraus,&lt;br /&gt;
z.B. für Skripte oder unbeaufsichtigte Bereitstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Agent jetzt und bei jedem Neustart starten (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung&lt;br /&gt;
(z.B. Einzelsitzung) die &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt;-Zeile weglassen&lt;br /&gt;
und nur &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt; ausführen.  Die&lt;br /&gt;
env-var-Zeile lässt sich ebenfalls weglassen, wenn&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; nur in der aktuellen Shell gebraucht&lt;br /&gt;
wird — dann statt der &amp;lt;code&amp;gt;[Environment]&amp;lt;/code&amp;gt;-Variante&lt;br /&gt;
&amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Auf stark abgespeckten Windows-Installationen ist der&lt;br /&gt;
ssh-agent-Dienst eventuell nicht vorhanden.  Einmalig nachrüsten&lt;br /&gt;
über &#039;&#039;&#039;Einstellungen → Apps → Optionale Features → OpenSSH-&lt;br /&gt;
Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative Agenten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — eigenes Protokoll; von ST/X&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Agent&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; unterstützt.  Schlüssel zu&lt;br /&gt;
OpenSSH migrieren.&lt;br /&gt;
* &#039;&#039;&#039;Git für Windows ssh-agent&#039;&#039;&#039; — funktioniert;&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; auf den dort veröffentlichten Socket&lt;br /&gt;
zeigen lassen.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — ein ST/X innerhalb der WSL sieht den WSL-eigenen Agent normal; ein ST/X auf der Windows-Seite nicht.  Eine Brücke per &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt; ist möglich.&lt;br /&gt;
&lt;br /&gt;
Prüfung über die Settings-Seite&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
die Anzeige dort meldet, ob das laufende Image den Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Windows-OpenSSH speichert agent-geladene Schlüssel &#039;&#039;&#039;nicht&#039;&#039;&#039;&lt;br /&gt;
über Agent-Neustarts hinweg.  Um nicht nach jedem Reboot manuell&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; aufrufen zu müssen, dieselbe Lazy-Load-&lt;br /&gt;
Konfiguration in &amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;&lt;br /&gt;
eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent&lt;br /&gt;
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige&lt;br /&gt;
Sitzung weiter.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Alle Stellschrauben sind klassenseitig auf&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; erreichbar:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Voreinstellung !! Steuert&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 Min) || Wie lange&lt;br /&gt;
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.&lt;br /&gt;
Liegt knapp unter dem typischen&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; des sshd,&lt;br /&gt;
damit wir uns recyceln, bevor der Server uns mit TCP-RESET&lt;br /&gt;
trennt.  &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; setzt auf Voreinstellung zurück.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Maximales Alter (s)&lt;br /&gt;
eines gecachten STAT, bevor &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; neu am&lt;br /&gt;
Server fragt.  Eltern-listDir stempelt ohnehin frische Attribute&lt;br /&gt;
auf alle Kinder, daher zahlt das Navigieren im offenen&lt;br /&gt;
Verzeichnis das TTL nicht.  &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; schaltet den Cache&lt;br /&gt;
ab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (Aktion) || Reißt jede&lt;br /&gt;
gepoolte Verbindung ab.  Nützlich nach einem bekannt schlechten&lt;br /&gt;
Netzereignis, vor einem bewussten Identitätswechsel oder zum&lt;br /&gt;
sauberen Image-Shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnose ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; über das Untermenü „Status&amp;quot; des&lt;br /&gt;
Launchers öffnen.  Der pro-Host-SFTP-Mutex erscheint als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;, der pool-weite Mutex als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Per Rechtsklick:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — schreibt den Walkback des letzten Eigners samt aller Waiter als Text in die Zwischenablage.  Unverzichtbar, wenn ein Prozess in&lt;br /&gt;
&amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; innerhalb von&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; klemmt.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — die ganze Tabelle, ideal für eine E-Mail-Diagnose.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS über den Wait-for-Graph, meldet Zyklen.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
Interessante Ereignisse werden über &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; geloggt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei automatischem Reconnect nach toter Verbindung.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei Idle-Verdrängung eines Pool-Eintrags.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; wenn eine SSH-Schlüsseldatei nicht geparst werden konnte — die Datei wird übersprungen.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nur SFTP v3.&#039;&#039;&#039;  Kein SETSTAT (kein entferntes chmod / chown / utime), kein SSH_FXP_READLINK exponiert (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; liefert immer &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; die normale stat-Info).  Einige&lt;br /&gt;
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische&lt;br /&gt;
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host.&#039;&#039;&#039;  Zwei gleichzeitige Operationen am selben Host stehen am Host-Mutex an.  Siehe [[#Ausblick]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt;-Fallback hat ein TOCTOU-Fenster.&#039;&#039;&#039; Bei Servern, die &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; ankündigen (jedes moderne OpenSSH tut das), ist das Überschreiben atomar. Beim seltenen Server, der das nicht tut, wird auf Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich dazwischenschieben.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; ist eine Heuristik.&#039;&#039;&#039; Liefert immer &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (die genaue Antwort würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).&lt;br /&gt;
&lt;br /&gt;
== Implementierungsdetails ==&lt;br /&gt;
&lt;br /&gt;
Für Leser, die die Architektur verstehen wollen.  Fünf Klassen,&lt;br /&gt;
von oben nach unten:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Aufgabe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename-Unterklasse, die&lt;br /&gt;
öffentliche API.  Bildet &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt;-URLs auf&lt;br /&gt;
entfernte Dateien ab und stellt &amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; usw. bereit.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3-Protokoll&lt;br /&gt;
(Request/Response-Codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Wird von SftpFilename angesteuert.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH-Kanal-Multiplexer (CHANNEL_OPEN,&lt;br /&gt;
DATA, EOF, CLOSE, WINDOW_ADJUST).  Eine logische Sitzung pro&lt;br /&gt;
Channel-Instanz.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-Level-SSH-Client: öffnet den&lt;br /&gt;
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und&lt;br /&gt;
verteilt anschließend Kanäle.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Drahtschicht.  Banner- und&lt;br /&gt;
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq /&lt;br /&gt;
recvSeq, Heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH-SFTP-Erweiterungen ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst&lt;br /&gt;
minimal gehalten.  OpenSSH bringt einen offenen&lt;br /&gt;
Erweiterungsmechanismus mit: der Server listet im&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;-Reply die Erweiterungsnamen auf, die&lt;br /&gt;
er versteht, und der Client ruft sie über&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt;-Pakete mit dem&lt;br /&gt;
Erweiterungsnamen als erstem String auf.  Jede Erweiterung wird&lt;br /&gt;
über &amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;&lt;br /&gt;
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie&lt;br /&gt;
nicht ankündigt.&lt;br /&gt;
&lt;br /&gt;
Der Stack nutzt heute vier OpenSSH-Erweiterungen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomares rename-mit-Überschreiben.  Wird automatisch von&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt; aufgegriffen; die&lt;br /&gt;
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum&lt;br /&gt;
Einsatz, die die Erweiterung nicht haben.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — Erzeugt einen POSIX-Hardlink. Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX-&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-typische Dateisystem-Statistik.&lt;br /&gt;
Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;;&lt;br /&gt;
das Ergebnis ist form-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;, sodass Aufrufer&lt;br /&gt;
lokale und entfernte Pfade einheitlich behandeln können.&lt;br /&gt;
Treibt den Menü-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; an,&lt;br /&gt;
der am Anfang dieser Seite beschrieben ist.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — schreibt den serverseitigen Schreibpuffer eines geöffneten Handles auf Platte.  Liegt als&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt; bereit; noch nicht&lt;br /&gt;
in eine &amp;quot;Durable-Write&amp;quot;-API auf Filename-Ebene eingebunden.&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden OpenSSH-Erweiterungen&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
werden in der angekündigten Liste erkannt, aber nicht auf&lt;br /&gt;
Filename-Ebene gekapselt — es gibt dafür noch keinen&lt;br /&gt;
Filename-seitigen Aufrufer.&lt;br /&gt;
&lt;br /&gt;
=== Verbindungs-Pooling ===&lt;br /&gt;
&lt;br /&gt;
Alle &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt;-Instanzen, die auf dasselbe Tripel&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; zeigen, teilen sich einen&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; samt einem &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Der Pool ist klassenseitig und wird von einem einzigen&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt; bewacht:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy-Aufbau&#039;&#039;&#039; — TCP + KEX + userauth + SFTP-INIT laufen erst beim ersten SFTP-Aufruf, nicht in &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host&#039;&#039;&#039; — SFTP-Anfragen an einen bestimmten Host werden durch einen &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; mit dem Namen &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; serialisiert (sichtbar im SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle-Verdrängung&#039;&#039;&#039; — ein Pool-Eintrag, der länger als&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt; ungenutzt liegt, wird beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet.&lt;br /&gt;
* &#039;&#039;&#039;Automatischer Reconnect&#039;&#039;&#039; — ein Fehler auf Transportebene (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den Pool-Eintrag, öffnet einen frischen Client und wiederholt die Anfrage &#039;&#039;&#039;einmal&#039;&#039;&#039;.  Anwendungsfehler aus SFTP-STATUS-Antworten werden sofort durchgereicht.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
&lt;br /&gt;
Geplant, aber noch nicht umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-Channel-Parallelität pro Host&#039;&#039;&#039; — aktuell bedeutet eine TCP- plus eine SFTP-Verbindung pro Host, dass N gleichzeitige Anfragen serialisieren.  Pipelining über mehrere SshClients im Pool (bevorzugt) oder ein transport-seitiger Reader-Prozess, der eingehende Pakete in Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel erlauben, weiter aufzulisten, während das Inhalts-Panel eine große Datei liest.&lt;br /&gt;
* &#039;&#039;&#039;Genaues &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen kann.&lt;br /&gt;
* &#039;&#039;&#039;SFTP-v5/v6-Aushandlung&#039;&#039;&#039; für erweiterte Attribute und FTP-artige Kanonisierung.  (Atomares Überschreibungs-rename ist bereits über die OpenSSH-Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; abgedeckt; siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]].)&lt;br /&gt;
&lt;br /&gt;
= Kommando-Shell =&lt;br /&gt;
&lt;br /&gt;
Lokale Kommando-Shell auf dieser expecco-Maschine.  Typische&lt;br /&gt;
Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm,&lt;br /&gt;
Brücke zwischen entferntem Workflow und lokalem Tool.&lt;br /&gt;
&lt;br /&gt;
Das RemoteAccess-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des&lt;br /&gt;
expecco-Prozesses.  Ausgaben gehen in das expecco-Log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warnung]] &#039;&#039;&#039;Telnet ist ein veraltetes&lt;br /&gt;
Protokoll ohne Verschlüsselung.&#039;&#039;&#039; Passwörter werden im Klartext&lt;br /&gt;
über die Leitung übertragen; jeder im Netzpfad kann sie lesen.&lt;br /&gt;
Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative&lt;br /&gt;
bietet (typisch: alte Industriesteuerungen, Laborgeräte,&lt;br /&gt;
eingebettete Messgeräte ohne SSH-Stack).  Für alles andere&lt;br /&gt;
[[#SSH und SFTP]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Das expecco-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (interne Demo)&lt;br /&gt;
&lt;br /&gt;
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler&lt;br /&gt;
8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für&lt;br /&gt;
Terminal-Optionen.  Verbindungsaufbau zum Ziel-Host:Port; nach&lt;br /&gt;
optionalem In-Band-Login können beide Seiten Daten senden.&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY, Agent-Weiterleitung, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks.&lt;br /&gt;
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack als HTTPS-Transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Netz]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31302</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31302"/>
		<updated>2026-05-26T10:33:01Z</updated>

		<summary type="html">&lt;p&gt;Sv: Fold bullet continuation lines onto a single physical line so MediaWiki keeps them inside &amp;lt;li&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on OpenSSL or libssh.  Use this for anything that touches credentials or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine. Used for local-tool integration and for the local end of a remote workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No encryption, passwords on the wire in clear.  Use only when the target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
&amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt; subclass that lets the rest of ST/X treat a remote SFTP path the same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of the filesystem holding the currently displayed directory.  Works uniformly for local paths and SFTP paths; for SFTP it requires the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; extension (every modern OpenSSH does).  Sizes are reported in IEC binary units (MiB, GiB, TiB) — the largest unit yielding a value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039; rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
&amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only; gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file unencrypted (agent-only mode ignores the passphrase, since the OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to &#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally; a ST/X on the Windows side does not.  Bridging needs a helper like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s walkback plus each waiter&#039;s, formatted as plain text.  Use when a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed (e.g. legacy PEM, encrypted-without-agent) — the file is skipped, others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime), no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
[[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every modern OpenSSH does), overwrite is atomic; on the rare server that does not, the receiver is emulated as delete-then-rename and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost three round-trips per directory icon, which made the original tree expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link. Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
&#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer to disk on an open handle.  Available on the low-level&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe, EOF, MNU on nil socket) evicts the dead pool entry, opens a fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP + one SFTP channel per host means N concurrent requests serialise.  Pipelining over multiple SshClients in the pool (preferred), or a transport-level reader process demultiplexing to per-channel inboxes, would let the tree pane keep listing while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (first batch only) + CLOSE — three RTTs per probe; needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style canonicalisation.  (Atomic-overwrite rename is already handled via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension; see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31301</id>
		<title>Remote Access</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31301"/>
		<updated>2026-05-26T10:33:00Z</updated>

		<summary type="html">&lt;p&gt;Sv: Fold bullet continuation lines onto a single physical line so MediaWiki keeps them inside &amp;lt;li&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fernzugriff&#039;&#039;&#039; bezeichnet die Möglichkeit, einen entfernten&lt;br /&gt;
Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus&lt;br /&gt;
zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu&lt;br /&gt;
verschieben oder ein Testgerät anzusteuern.  Drei Protokoll-Familien&lt;br /&gt;
sind unterstützt, in absteigender Empfehlungsreihenfolge:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH und SFTP&#039;&#039;&#039; (empfohlen) — verschlüsselte Shell und sichere Dateiübertragung über einen SSH-2-Tunnel.  Reine Smalltalk-Implementierung in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; keine externe Abhängigkeit von OpenSSL oder libssh.  Für alles mit Zugangsdaten oder sensiblen Nutzdaten.&lt;br /&gt;
* &#039;&#039;&#039;Lokale Kommando-Shell&#039;&#039;&#039; — fork + exec auf der lokalen Maschine.  Für die Anbindung lokaler Werkzeuge und für die lokale Seite eines hybriden Workflows.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (veraltet) — Klartext-Terminalsitzung.  Keine Verschlüsselung, Passwörter im Klartext auf der Leitung.  Nur einsetzen, wenn die Gegenstelle keine Alternative bietet.&lt;br /&gt;
&lt;br /&gt;
= SSH und SFTP =&lt;br /&gt;
&lt;br /&gt;
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab&lt;br /&gt;
(RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der&lt;br /&gt;
chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das&lt;br /&gt;
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02).  Zwei Schichten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatischer SSH-Zugriff (entferntes &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY-Shell, Agent-Weiterleitung, ProxyJump-Bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — eine&lt;br /&gt;
&amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;-Unterklasse, die es dem restlichen ST/X&lt;br /&gt;
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale&lt;br /&gt;
Datei.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut:&lt;br /&gt;
zuerst das, was der Anwender sieht und tut, darunter die&lt;br /&gt;
expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails&lt;br /&gt;
für Interessierte.&lt;br /&gt;
&lt;br /&gt;
== Aus dem FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Im Adress-Dropdown eine &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt;-URL einfügen.  Der&lt;br /&gt;
Browser-Tab füllt sich wie bei einem lokalen Pfad.&lt;br /&gt;
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),&lt;br /&gt;
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich&lt;br /&gt;
normal.  Der erste Klick auf einen Host dauert ~200–500 ms&lt;br /&gt;
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte&lt;br /&gt;
Verbindung weiter.&lt;br /&gt;
&lt;br /&gt;
URL-Syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlt &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;, wird der lokale Login-Name verwendet, Port&lt;br /&gt;
ist standardmäßig 22, Pfad standardmäßig &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Menü &#039;&#039;&#039;Tools&#039;&#039;&#039; im FileBrowserV2 bietet vier Aktionen — die&lt;br /&gt;
drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek&lt;br /&gt;
sichtbar:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — öffnet den Schlüsselerzeugungs-Dialog, siehe [[#Einen SSH-Schlüssel erzeugen]] unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — öffnet ein interaktives VT100-Terminal zu einem entfernten Host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — navigiert diesen Browser-Tab über SFTP auf ein entferntes Dateisystem.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — zeigt Größe, freien Platz und Belegung des Dateisystems, das das aktuell angezeigte Verzeichnis enthält. Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP setzt der Aufruf voraus, daß der Server die Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; ankündigt (jedes moderne OpenSSH&lt;br /&gt;
tut das).  Größen werden in IEC-Binäreinheiten ausgegeben (MiB,&lt;br /&gt;
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1&lt;br /&gt;
liefert, damit ein TB-großes Volume als &#039;&#039;X TiB&#039;&#039; statt&lt;br /&gt;
&#039;&#039;10240 GiB&#039;&#039; erscheint.&lt;br /&gt;
&lt;br /&gt;
== Aus expecco-Aktionen ==&lt;br /&gt;
&lt;br /&gt;
Das Expecco-RemoteAccess-Plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) stellt folgende Testaktionen&lt;br /&gt;
in der expecco-Aktionspalette bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — öffnet eine SSH-Sitzung über das plattformeigene &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;-Binary (PuTTYs &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; unter Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.&lt;br /&gt;
&lt;br /&gt;
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater&lt;br /&gt;
Schlüssel auf dieser Maschine, öffentlicher Teil in der&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des Zielhosts).  Schlüssel&lt;br /&gt;
erzeugen entweder über den Dialog unten oder über&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Plugin fügt zusätzlich eine Settings-Seite hinzu:&lt;br /&gt;
&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039; mit&lt;br /&gt;
einer einzelnen Schaltfläche &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039;, die&lt;br /&gt;
denselben Dialog öffnet.&lt;br /&gt;
&lt;br /&gt;
== Einen SSH-Schlüssel erzeugen ==&lt;br /&gt;
&lt;br /&gt;
=== Der Dialog (FileBrowserV2 / Settings-Seite) ===&lt;br /&gt;
&lt;br /&gt;
Der Dialog fragt alle Parameter in einem Formular ab:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — wird in den erzeugten Schlüssel eingebettet (Voreinstellung &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — schreibt&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (oder wohin man will) samt&lt;br /&gt;
zugehöriger &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;-Datei daneben.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — schreibt die Datei UND übergibt den Schlüssel dem laufenden ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — der Schlüssel lebt nur im Speicher des Agents; nach Agent-Neustart ist er verloren.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — vollständiger Pfad; ausgegraut im Agent-only-Modus.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — leer lässt die On-Disk-Datei unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten Schlüssel transportiert).&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;Generate&#039;&#039;&#039; wird die Public-Key-Zeile (dieselbe&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt;-Zeichenfolge, die&lt;br /&gt;
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum&lt;br /&gt;
direkten Einfügen in die &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des&lt;br /&gt;
Zielhosts.&lt;br /&gt;
&lt;br /&gt;
=== Aus einem Workspace ===&lt;br /&gt;
&lt;br /&gt;
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; einen reinen Smalltalk-Schlüsselgenerator&lt;br /&gt;
bereit, dessen Ausgabe bit-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt; ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Passphrase-verschlüsselt auf Platte speichern&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ UND in den laufenden Agent laden&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll&lt;br /&gt;
interoperabel (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; rekonstruiert den&lt;br /&gt;
öffentlichen Schlüssel, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; ändert&lt;br /&gt;
die Passphrase usw.).&lt;br /&gt;
&lt;br /&gt;
=== Mit den Shell-Werkzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der klassische Weg funktioniert weiterhin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ssh-agent vorbereiten ==&lt;br /&gt;
&lt;br /&gt;
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien&lt;br /&gt;
deutlich vorzuziehen: er hält verschlüsselte private Schlüssel&lt;br /&gt;
einmal pro Sitzung entsperrt und kann Identitäten verwalten&lt;br /&gt;
(hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X&lt;br /&gt;
nie direkt sehen soll.&lt;br /&gt;
&lt;br /&gt;
ST/X erkennt den Agent-Pfad automatisch, sobald&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;zum Zeitpunkt des Starts von stx&#039;&#039;&#039;&lt;br /&gt;
in der Prozessumgebung gesetzt ist.  Eine spätere Zuweisung aus&lt;br /&gt;
einem Workspace nützt nichts.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Die meisten Desktop-Distributionen starten einen Agent automatisch&lt;br /&gt;
beim Login (gnome-keyring unter GNOME, ssh-agent.service unter&lt;br /&gt;
systemd, KWallet unter KDE).  Prüfen im Terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh oder ähnlich&lt;br /&gt;
ssh-add -l             # listet geladene Identitäten&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # eigene laden, falls nicht da&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei&lt;br /&gt;
aufnehmen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc oder ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X muss aus einer Shell gestartet werden, die diese rc bereits&lt;br /&gt;
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die&lt;br /&gt;
Variable nicht.  Empfehlung: ein kleines Wrapper-Skript unter&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt;, das die rc sourcet und dann stx&lt;br /&gt;
startet.&lt;br /&gt;
&lt;br /&gt;
Die Settings-Seite (&#039;&#039;&#039;Extras → Settings → Plugins → Remote&lt;br /&gt;
Access — SSH Keys&#039;&#039;&#039;) zeigt an, ob das laufende Image einen&lt;br /&gt;
Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Permanente Einrichtung via systemd ====&lt;br /&gt;
&lt;br /&gt;
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-&lt;br /&gt;
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den&lt;br /&gt;
meisten Distros mit dem Paket &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
ausgelieferte Per-User-systemd-Unit aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; in der Shell-rc auf den&lt;br /&gt;
User-Service-Socket zeigen lassen (ersetzt das&lt;br /&gt;
&amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;-Snippet oben):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Um den manuellen &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt;-Schritt zu sparen, kann&lt;br /&gt;
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.&lt;br /&gt;
In &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt; eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und&lt;br /&gt;
übergibt den entsperrten Schlüssel an den Agent; weitere&lt;br /&gt;
Verbindungen nutzen die gespeicherte Identität ohne Prompt.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit.&lt;br /&gt;
Einmalige Einrichtung:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Dienste&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) als Administrator öffnen.&lt;br /&gt;
# &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039; suchen, Starttyp auf &#039;&#039;&#039;Automatisch&#039;&#039;&#039; setzen, &#039;&#039;&#039;Starten&#039;&#039;&#039; anklicken.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Prüfen: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), nicht auf einem&lt;br /&gt;
Unix-Socket.  ST/X unterstützt beide Transporte, jedoch setzt das&lt;br /&gt;
Windows-ssh-add &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; selbst.&lt;br /&gt;
Daher einmalig systemweit setzen:&lt;br /&gt;
&lt;br /&gt;
# {{Key|Win}} drücken → &amp;quot;Umgebungsvariablen&amp;quot; → „Systemumgebungs- variablen bearbeiten&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Umgebungsvariablen&#039;&#039;&#039; → unter &#039;&#039;&#039;Benutzervariablen&#039;&#039;&#039;, &#039;&#039;&#039;Neu&#039;&#039;&#039; klicken.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Wert: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ab- und wieder anmelden (oder stx neu starten), damit die neue Umgebung übernommen wird.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell-Schnelleinrichtung ====&lt;br /&gt;
&lt;br /&gt;
Derselbe Aufbau aus einer &#039;&#039;&#039;Administrator-PowerShell&#039;&#039;&#039; heraus,&lt;br /&gt;
z.B. für Skripte oder unbeaufsichtigte Bereitstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Agent jetzt und bei jedem Neustart starten (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung&lt;br /&gt;
(z.B. Einzelsitzung) die &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt;-Zeile weglassen&lt;br /&gt;
und nur &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt; ausführen.  Die&lt;br /&gt;
env-var-Zeile lässt sich ebenfalls weglassen, wenn&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; nur in der aktuellen Shell gebraucht&lt;br /&gt;
wird — dann statt der &amp;lt;code&amp;gt;[Environment]&amp;lt;/code&amp;gt;-Variante&lt;br /&gt;
&amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Auf stark abgespeckten Windows-Installationen ist der&lt;br /&gt;
ssh-agent-Dienst eventuell nicht vorhanden.  Einmalig nachrüsten&lt;br /&gt;
über &#039;&#039;&#039;Einstellungen → Apps → Optionale Features → OpenSSH-&lt;br /&gt;
Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative Agenten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — eigenes Protokoll; von ST/X&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Agent&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; unterstützt.  Schlüssel zu&lt;br /&gt;
OpenSSH migrieren.&lt;br /&gt;
* &#039;&#039;&#039;Git für Windows ssh-agent&#039;&#039;&#039; — funktioniert;&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; auf den dort veröffentlichten Socket&lt;br /&gt;
zeigen lassen.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — ein ST/X innerhalb der WSL sieht den WSL-eigenen Agent normal; ein ST/X auf der Windows-Seite nicht.  Eine Brücke per &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt; ist möglich.&lt;br /&gt;
&lt;br /&gt;
Prüfung über die Settings-Seite&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
die Anzeige dort meldet, ob das laufende Image den Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Windows-OpenSSH speichert agent-geladene Schlüssel &#039;&#039;&#039;nicht&#039;&#039;&#039;&lt;br /&gt;
über Agent-Neustarts hinweg.  Um nicht nach jedem Reboot manuell&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; aufrufen zu müssen, dieselbe Lazy-Load-&lt;br /&gt;
Konfiguration in &amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;&lt;br /&gt;
eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent&lt;br /&gt;
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige&lt;br /&gt;
Sitzung weiter.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Alle Stellschrauben sind klassenseitig auf&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; erreichbar:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Voreinstellung !! Steuert&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 Min) || Wie lange&lt;br /&gt;
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.&lt;br /&gt;
Liegt knapp unter dem typischen&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; des sshd,&lt;br /&gt;
damit wir uns recyceln, bevor der Server uns mit TCP-RESET&lt;br /&gt;
trennt.  &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; setzt auf Voreinstellung zurück.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Maximales Alter (s)&lt;br /&gt;
eines gecachten STAT, bevor &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; neu am&lt;br /&gt;
Server fragt.  Eltern-listDir stempelt ohnehin frische Attribute&lt;br /&gt;
auf alle Kinder, daher zahlt das Navigieren im offenen&lt;br /&gt;
Verzeichnis das TTL nicht.  &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; schaltet den Cache&lt;br /&gt;
ab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (Aktion) || Reißt jede&lt;br /&gt;
gepoolte Verbindung ab.  Nützlich nach einem bekannt schlechten&lt;br /&gt;
Netzereignis, vor einem bewussten Identitätswechsel oder zum&lt;br /&gt;
sauberen Image-Shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnose ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; über das Untermenü „Status&amp;quot; des&lt;br /&gt;
Launchers öffnen.  Der pro-Host-SFTP-Mutex erscheint als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;, der pool-weite Mutex als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Per Rechtsklick:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — schreibt den Walkback des letzten Eigners samt aller Waiter als Text in die Zwischenablage.  Unverzichtbar, wenn ein Prozess in&lt;br /&gt;
&amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; innerhalb von&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; klemmt.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — die ganze Tabelle, ideal für eine E-Mail-Diagnose.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS über den Wait-for-Graph, meldet Zyklen.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
Interessante Ereignisse werden über &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; geloggt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei automatischem Reconnect nach toter Verbindung.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei Idle-Verdrängung eines Pool-Eintrags.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; wenn eine SSH-Schlüsseldatei nicht geparst werden konnte — die Datei wird übersprungen.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nur SFTP v3.&#039;&#039;&#039;  Kein SETSTAT (kein entferntes chmod / chown / utime), kein SSH_FXP_READLINK exponiert (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; liefert immer &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; die normale stat-Info).  Einige&lt;br /&gt;
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische&lt;br /&gt;
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host.&#039;&#039;&#039;  Zwei gleichzeitige Operationen am selben Host stehen am Host-Mutex an.  Siehe [[#Ausblick]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt;-Fallback hat ein TOCTOU-Fenster.&#039;&#039;&#039; Bei Servern, die &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; ankündigen (jedes moderne OpenSSH tut das), ist das Überschreiben atomar. Beim seltenen Server, der das nicht tut, wird auf Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich dazwischenschieben.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; ist eine Heuristik.&#039;&#039;&#039; Liefert immer &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (die genaue Antwort würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).&lt;br /&gt;
&lt;br /&gt;
== Implementierungsdetails ==&lt;br /&gt;
&lt;br /&gt;
Für Leser, die die Architektur verstehen wollen.  Fünf Klassen,&lt;br /&gt;
von oben nach unten:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Aufgabe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename-Unterklasse, die&lt;br /&gt;
öffentliche API.  Bildet &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt;-URLs auf&lt;br /&gt;
entfernte Dateien ab und stellt &amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; usw. bereit.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3-Protokoll&lt;br /&gt;
(Request/Response-Codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Wird von SftpFilename angesteuert.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH-Kanal-Multiplexer (CHANNEL_OPEN,&lt;br /&gt;
DATA, EOF, CLOSE, WINDOW_ADJUST).  Eine logische Sitzung pro&lt;br /&gt;
Channel-Instanz.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-Level-SSH-Client: öffnet den&lt;br /&gt;
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und&lt;br /&gt;
verteilt anschließend Kanäle.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Drahtschicht.  Banner- und&lt;br /&gt;
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq /&lt;br /&gt;
recvSeq, Heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH-SFTP-Erweiterungen ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst&lt;br /&gt;
minimal gehalten.  OpenSSH bringt einen offenen&lt;br /&gt;
Erweiterungsmechanismus mit: der Server listet im&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;-Reply die Erweiterungsnamen auf, die&lt;br /&gt;
er versteht, und der Client ruft sie über&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt;-Pakete mit dem&lt;br /&gt;
Erweiterungsnamen als erstem String auf.  Jede Erweiterung wird&lt;br /&gt;
über &amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;&lt;br /&gt;
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie&lt;br /&gt;
nicht ankündigt.&lt;br /&gt;
&lt;br /&gt;
Der Stack nutzt heute vier OpenSSH-Erweiterungen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomares rename-mit-Überschreiben.  Wird automatisch von&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt; aufgegriffen; die&lt;br /&gt;
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum&lt;br /&gt;
Einsatz, die die Erweiterung nicht haben.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — Erzeugt einen POSIX-Hardlink. Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX-&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-typische Dateisystem-Statistik.&lt;br /&gt;
Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;;&lt;br /&gt;
das Ergebnis ist form-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;, sodass Aufrufer&lt;br /&gt;
lokale und entfernte Pfade einheitlich behandeln können.&lt;br /&gt;
Treibt den Menü-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; an,&lt;br /&gt;
der am Anfang dieser Seite beschrieben ist.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — schreibt den serverseitigen Schreibpuffer eines geöffneten Handles auf Platte.  Liegt als&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt; bereit; noch nicht&lt;br /&gt;
in eine &amp;quot;Durable-Write&amp;quot;-API auf Filename-Ebene eingebunden.&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden OpenSSH-Erweiterungen&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
werden in der angekündigten Liste erkannt, aber nicht auf&lt;br /&gt;
Filename-Ebene gekapselt — es gibt dafür noch keinen&lt;br /&gt;
Filename-seitigen Aufrufer.&lt;br /&gt;
&lt;br /&gt;
=== Verbindungs-Pooling ===&lt;br /&gt;
&lt;br /&gt;
Alle &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt;-Instanzen, die auf dasselbe Tripel&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; zeigen, teilen sich einen&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; samt einem &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Der Pool ist klassenseitig und wird von einem einzigen&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt; bewacht:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy-Aufbau&#039;&#039;&#039; — TCP + KEX + userauth + SFTP-INIT laufen erst beim ersten SFTP-Aufruf, nicht in &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host&#039;&#039;&#039; — SFTP-Anfragen an einen bestimmten Host werden durch einen &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; mit dem Namen &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; serialisiert (sichtbar im SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle-Verdrängung&#039;&#039;&#039; — ein Pool-Eintrag, der länger als&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt; ungenutzt liegt, wird beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet.&lt;br /&gt;
* &#039;&#039;&#039;Automatischer Reconnect&#039;&#039;&#039; — ein Fehler auf Transportebene (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den Pool-Eintrag, öffnet einen frischen Client und wiederholt die Anfrage &#039;&#039;&#039;einmal&#039;&#039;&#039;.  Anwendungsfehler aus SFTP-STATUS-Antworten werden sofort durchgereicht.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
&lt;br /&gt;
Geplant, aber noch nicht umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-Channel-Parallelität pro Host&#039;&#039;&#039; — aktuell bedeutet eine TCP- plus eine SFTP-Verbindung pro Host, dass N gleichzeitige Anfragen serialisieren.  Pipelining über mehrere SshClients im Pool (bevorzugt) oder ein transport-seitiger Reader-Prozess, der eingehende Pakete in Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel erlauben, weiter aufzulisten, während das Inhalts-Panel eine große Datei liest.&lt;br /&gt;
* &#039;&#039;&#039;Genaues &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen kann.&lt;br /&gt;
* &#039;&#039;&#039;SFTP-v5/v6-Aushandlung&#039;&#039;&#039; für erweiterte Attribute und FTP-artige Kanonisierung.  (Atomares Überschreibungs-rename ist bereits über die OpenSSH-Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; abgedeckt; siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]].)&lt;br /&gt;
&lt;br /&gt;
= Kommando-Shell =&lt;br /&gt;
&lt;br /&gt;
Lokale Kommando-Shell auf dieser expecco-Maschine.  Typische&lt;br /&gt;
Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm,&lt;br /&gt;
Brücke zwischen entferntem Workflow und lokalem Tool.&lt;br /&gt;
&lt;br /&gt;
Das RemoteAccess-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des&lt;br /&gt;
expecco-Prozesses.  Ausgaben gehen in das expecco-Log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warnung]] &#039;&#039;&#039;Telnet ist ein veraltetes&lt;br /&gt;
Protokoll ohne Verschlüsselung.&#039;&#039;&#039; Passwörter werden im Klartext&lt;br /&gt;
über die Leitung übertragen; jeder im Netzpfad kann sie lesen.&lt;br /&gt;
Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative&lt;br /&gt;
bietet (typisch: alte Industriesteuerungen, Laborgeräte,&lt;br /&gt;
eingebettete Messgeräte ohne SSH-Stack).  Für alles andere&lt;br /&gt;
[[#SSH und SFTP]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Das expecco-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (interne Demo)&lt;br /&gt;
&lt;br /&gt;
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler&lt;br /&gt;
8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für&lt;br /&gt;
Terminal-Optionen.  Verbindungsaufbau zum Ziel-Host:Port; nach&lt;br /&gt;
optionalem In-Band-Login können beide Seiten Daten senden.&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY, Agent-Weiterleitung, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks.&lt;br /&gt;
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack als HTTPS-Transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Netz]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31300</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31300"/>
		<updated>2026-05-26T10:29:04Z</updated>

		<summary type="html">&lt;p&gt;Sv: Remove 2-space continuation-line indent (was triggering MediaWiki &amp;lt;pre&amp;gt;)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure&lt;br /&gt;
file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation&lt;br /&gt;
in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on&lt;br /&gt;
OpenSSL or libssh.  Use this for anything that touches credentials&lt;br /&gt;
or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine.&lt;br /&gt;
Used for local-tool integration and for the local end of a remote&lt;br /&gt;
workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No&lt;br /&gt;
encryption, passwords on the wire in clear.  Use only when the&lt;br /&gt;
target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
&amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;&lt;br /&gt;
subclass that lets the rest of ST/X treat a remote SFTP path the&lt;br /&gt;
same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation&lt;br /&gt;
dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a&lt;br /&gt;
remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote&lt;br /&gt;
filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of&lt;br /&gt;
the filesystem holding the currently displayed directory.  Works&lt;br /&gt;
uniformly for local paths and SFTP paths; for SFTP it requires&lt;br /&gt;
the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt;&lt;br /&gt;
extension (every modern OpenSSH does).  Sizes are reported in&lt;br /&gt;
IEC binary units (MiB, GiB, TiB) — the largest unit yielding a&lt;br /&gt;
value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039;&lt;br /&gt;
rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session&lt;br /&gt;
via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same&lt;br /&gt;
but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
&amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt;&lt;br /&gt;
(or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and&lt;br /&gt;
also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only;&lt;br /&gt;
gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file&lt;br /&gt;
unencrypted (agent-only mode ignores the passphrase, since the&lt;br /&gt;
OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to&lt;br /&gt;
&#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by&lt;br /&gt;
ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally;&lt;br /&gt;
a ST/X on the Windows side does not.  Bridging needs a helper&lt;br /&gt;
like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s&lt;br /&gt;
walkback plus each waiter&#039;s, formatted as plain text.  Use when&lt;br /&gt;
a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an&lt;br /&gt;
email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports&lt;br /&gt;
cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed&lt;br /&gt;
(e.g. legacy PEM, encrypted-without-agent) — the file is skipped,&lt;br /&gt;
others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime),&lt;br /&gt;
no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
[[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the&lt;br /&gt;
same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On&lt;br /&gt;
servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every&lt;br /&gt;
modern OpenSSH does), overwrite is atomic; on the rare server&lt;br /&gt;
that does not, the receiver is emulated as delete-then-rename&lt;br /&gt;
and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always&lt;br /&gt;
returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost&lt;br /&gt;
three round-trips per directory icon, which made the original tree&lt;br /&gt;
expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic&lt;br /&gt;
rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link.&lt;br /&gt;
Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
&#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer&lt;br /&gt;
to disk on an open handle.  Available on the low-level&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens&lt;br /&gt;
on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host&lt;br /&gt;
are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe,&lt;br /&gt;
EOF, MNU on nil socket) evicts the dead pool entry, opens a&lt;br /&gt;
fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level&lt;br /&gt;
SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP +&lt;br /&gt;
one SFTP channel per host means N concurrent requests&lt;br /&gt;
serialise.  Pipelining over multiple SshClients in the pool&lt;br /&gt;
(preferred), or a transport-level reader process demultiplexing&lt;br /&gt;
to per-channel inboxes, would let the tree pane keep listing&lt;br /&gt;
while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR&lt;br /&gt;
+ READ_DIR (first batch only) + CLOSE — three RTTs per probe;&lt;br /&gt;
needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style&lt;br /&gt;
canonicalisation.  (Atomic-overwrite rename is already handled&lt;br /&gt;
via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension;&lt;br /&gt;
see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent&lt;br /&gt;
forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of&lt;br /&gt;
this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack&lt;br /&gt;
for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31299</id>
		<title>Remote Access</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31299"/>
		<updated>2026-05-26T10:29:02Z</updated>

		<summary type="html">&lt;p&gt;Sv: Remove 2-space continuation-line indent (was triggering MediaWiki &amp;lt;pre&amp;gt;)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fernzugriff&#039;&#039;&#039; bezeichnet die Möglichkeit, einen entfernten&lt;br /&gt;
Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus&lt;br /&gt;
zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu&lt;br /&gt;
verschieben oder ein Testgerät anzusteuern.  Drei Protokoll-Familien&lt;br /&gt;
sind unterstützt, in absteigender Empfehlungsreihenfolge:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH und SFTP&#039;&#039;&#039; (empfohlen) — verschlüsselte Shell und sichere&lt;br /&gt;
Dateiübertragung über einen SSH-2-Tunnel.  Reine&lt;br /&gt;
Smalltalk-Implementierung in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;;&lt;br /&gt;
keine externe Abhängigkeit von OpenSSL oder libssh.  Für alles&lt;br /&gt;
mit Zugangsdaten oder sensiblen Nutzdaten.&lt;br /&gt;
* &#039;&#039;&#039;Lokale Kommando-Shell&#039;&#039;&#039; — fork + exec auf der lokalen&lt;br /&gt;
Maschine.  Für die Anbindung lokaler Werkzeuge und für die&lt;br /&gt;
lokale Seite eines hybriden Workflows.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (veraltet) — Klartext-Terminalsitzung.  Keine&lt;br /&gt;
Verschlüsselung, Passwörter im Klartext auf der Leitung.  Nur&lt;br /&gt;
einsetzen, wenn die Gegenstelle keine Alternative bietet.&lt;br /&gt;
&lt;br /&gt;
= SSH und SFTP =&lt;br /&gt;
&lt;br /&gt;
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab&lt;br /&gt;
(RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der&lt;br /&gt;
chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das&lt;br /&gt;
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02).  Zwei Schichten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatischer SSH-Zugriff&lt;br /&gt;
(entferntes &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY-Shell, Agent-Weiterleitung,&lt;br /&gt;
ProxyJump-Bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — eine&lt;br /&gt;
&amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;-Unterklasse, die es dem restlichen ST/X&lt;br /&gt;
erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale&lt;br /&gt;
Datei.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut:&lt;br /&gt;
zuerst das, was der Anwender sieht und tut, darunter die&lt;br /&gt;
expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails&lt;br /&gt;
für Interessierte.&lt;br /&gt;
&lt;br /&gt;
== Aus dem FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Im Adress-Dropdown eine &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt;-URL einfügen.  Der&lt;br /&gt;
Browser-Tab füllt sich wie bei einem lokalen Pfad.&lt;br /&gt;
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),&lt;br /&gt;
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich&lt;br /&gt;
normal.  Der erste Klick auf einen Host dauert ~200–500 ms&lt;br /&gt;
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte&lt;br /&gt;
Verbindung weiter.&lt;br /&gt;
&lt;br /&gt;
URL-Syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlt &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;, wird der lokale Login-Name verwendet, Port&lt;br /&gt;
ist standardmäßig 22, Pfad standardmäßig &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Menü &#039;&#039;&#039;Tools&#039;&#039;&#039; im FileBrowserV2 bietet vier Aktionen — die&lt;br /&gt;
drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek&lt;br /&gt;
sichtbar:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — öffnet den&lt;br /&gt;
Schlüsselerzeugungs-Dialog, siehe&lt;br /&gt;
[[#Einen SSH-Schlüssel erzeugen]] unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — öffnet ein interaktives VT100-Terminal&lt;br /&gt;
zu einem entfernten Host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — navigiert diesen Browser-Tab über SFTP&lt;br /&gt;
auf ein entferntes Dateisystem.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — zeigt Größe, freien Platz und Belegung&lt;br /&gt;
des Dateisystems, das das aktuell angezeigte Verzeichnis enthält.&lt;br /&gt;
Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP&lt;br /&gt;
setzt der Aufruf voraus, daß der Server die Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; ankündigt (jedes moderne OpenSSH&lt;br /&gt;
tut das).  Größen werden in IEC-Binäreinheiten ausgegeben (MiB,&lt;br /&gt;
GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1&lt;br /&gt;
liefert, damit ein TB-großes Volume als &#039;&#039;X TiB&#039;&#039; statt&lt;br /&gt;
&#039;&#039;10240 GiB&#039;&#039; erscheint.&lt;br /&gt;
&lt;br /&gt;
== Aus expecco-Aktionen ==&lt;br /&gt;
&lt;br /&gt;
Das Expecco-RemoteAccess-Plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) stellt folgende Testaktionen&lt;br /&gt;
in der expecco-Aktionspalette bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — öffnet eine&lt;br /&gt;
SSH-Sitzung über das plattformeigene &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;-Binary&lt;br /&gt;
(PuTTYs &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; unter Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; —&lt;br /&gt;
dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.&lt;br /&gt;
&lt;br /&gt;
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater&lt;br /&gt;
Schlüssel auf dieser Maschine, öffentlicher Teil in der&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des Zielhosts).  Schlüssel&lt;br /&gt;
erzeugen entweder über den Dialog unten oder über&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Plugin fügt zusätzlich eine Settings-Seite hinzu:&lt;br /&gt;
&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039; mit&lt;br /&gt;
einer einzelnen Schaltfläche &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039;, die&lt;br /&gt;
denselben Dialog öffnet.&lt;br /&gt;
&lt;br /&gt;
== Einen SSH-Schlüssel erzeugen ==&lt;br /&gt;
&lt;br /&gt;
=== Der Dialog (FileBrowserV2 / Settings-Seite) ===&lt;br /&gt;
&lt;br /&gt;
Der Dialog fragt alle Parameter in einem Formular ab:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — wird in den erzeugten Schlüssel eingebettet&lt;br /&gt;
(Voreinstellung &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — schreibt&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (oder wohin man will) samt&lt;br /&gt;
zugehöriger &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;-Datei daneben.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — schreibt die Datei&lt;br /&gt;
UND übergibt den Schlüssel dem laufenden ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — der Schlüssel lebt nur im&lt;br /&gt;
Speicher des Agents; nach Agent-Neustart ist er verloren.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — vollständiger Pfad; ausgegraut im&lt;br /&gt;
Agent-only-Modus.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — leer lässt die On-Disk-Datei&lt;br /&gt;
unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da&lt;br /&gt;
das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten&lt;br /&gt;
Schlüssel transportiert).&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;Generate&#039;&#039;&#039; wird die Public-Key-Zeile (dieselbe&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt;-Zeichenfolge, die&lt;br /&gt;
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum&lt;br /&gt;
direkten Einfügen in die &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des&lt;br /&gt;
Zielhosts.&lt;br /&gt;
&lt;br /&gt;
=== Aus einem Workspace ===&lt;br /&gt;
&lt;br /&gt;
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; einen reinen Smalltalk-Schlüsselgenerator&lt;br /&gt;
bereit, dessen Ausgabe bit-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt; ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Passphrase-verschlüsselt auf Platte speichern&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ UND in den laufenden Agent laden&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll&lt;br /&gt;
interoperabel (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; rekonstruiert den&lt;br /&gt;
öffentlichen Schlüssel, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; ändert&lt;br /&gt;
die Passphrase usw.).&lt;br /&gt;
&lt;br /&gt;
=== Mit den Shell-Werkzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der klassische Weg funktioniert weiterhin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ssh-agent vorbereiten ==&lt;br /&gt;
&lt;br /&gt;
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien&lt;br /&gt;
deutlich vorzuziehen: er hält verschlüsselte private Schlüssel&lt;br /&gt;
einmal pro Sitzung entsperrt und kann Identitäten verwalten&lt;br /&gt;
(hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X&lt;br /&gt;
nie direkt sehen soll.&lt;br /&gt;
&lt;br /&gt;
ST/X erkennt den Agent-Pfad automatisch, sobald&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;zum Zeitpunkt des Starts von stx&#039;&#039;&#039;&lt;br /&gt;
in der Prozessumgebung gesetzt ist.  Eine spätere Zuweisung aus&lt;br /&gt;
einem Workspace nützt nichts.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Die meisten Desktop-Distributionen starten einen Agent automatisch&lt;br /&gt;
beim Login (gnome-keyring unter GNOME, ssh-agent.service unter&lt;br /&gt;
systemd, KWallet unter KDE).  Prüfen im Terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh oder ähnlich&lt;br /&gt;
ssh-add -l             # listet geladene Identitäten&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # eigene laden, falls nicht da&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei&lt;br /&gt;
aufnehmen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc oder ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X muss aus einer Shell gestartet werden, die diese rc bereits&lt;br /&gt;
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die&lt;br /&gt;
Variable nicht.  Empfehlung: ein kleines Wrapper-Skript unter&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt;, das die rc sourcet und dann stx&lt;br /&gt;
startet.&lt;br /&gt;
&lt;br /&gt;
Die Settings-Seite (&#039;&#039;&#039;Extras → Settings → Plugins → Remote&lt;br /&gt;
Access — SSH Keys&#039;&#039;&#039;) zeigt an, ob das laufende Image einen&lt;br /&gt;
Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Permanente Einrichtung via systemd ====&lt;br /&gt;
&lt;br /&gt;
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-&lt;br /&gt;
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den&lt;br /&gt;
meisten Distros mit dem Paket &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
ausgelieferte Per-User-systemd-Unit aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; in der Shell-rc auf den&lt;br /&gt;
User-Service-Socket zeigen lassen (ersetzt das&lt;br /&gt;
&amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;-Snippet oben):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Um den manuellen &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt;-Schritt zu sparen, kann&lt;br /&gt;
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.&lt;br /&gt;
In &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt; eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und&lt;br /&gt;
übergibt den entsperrten Schlüssel an den Agent; weitere&lt;br /&gt;
Verbindungen nutzen die gespeicherte Identität ohne Prompt.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit.&lt;br /&gt;
Einmalige Einrichtung:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Dienste&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) als Administrator öffnen.&lt;br /&gt;
# &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039; suchen, Starttyp auf&lt;br /&gt;
&#039;&#039;&#039;Automatisch&#039;&#039;&#039; setzen, &#039;&#039;&#039;Starten&#039;&#039;&#039; anklicken.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Prüfen: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), nicht auf einem&lt;br /&gt;
Unix-Socket.  ST/X unterstützt beide Transporte, jedoch setzt das&lt;br /&gt;
Windows-ssh-add &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; selbst.&lt;br /&gt;
Daher einmalig systemweit setzen:&lt;br /&gt;
&lt;br /&gt;
# {{Key|Win}} drücken → &amp;quot;Umgebungsvariablen&amp;quot; → „Systemumgebungs-&lt;br /&gt;
variablen bearbeiten&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Umgebungsvariablen&#039;&#039;&#039; → unter &#039;&#039;&#039;Benutzervariablen&#039;&#039;&#039;,&lt;br /&gt;
&#039;&#039;&#039;Neu&#039;&#039;&#039; klicken.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Wert: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ab- und wieder anmelden (oder stx neu starten), damit die neue&lt;br /&gt;
Umgebung übernommen wird.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell-Schnelleinrichtung ====&lt;br /&gt;
&lt;br /&gt;
Derselbe Aufbau aus einer &#039;&#039;&#039;Administrator-PowerShell&#039;&#039;&#039; heraus,&lt;br /&gt;
z.B. für Skripte oder unbeaufsichtigte Bereitstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Agent jetzt und bei jedem Neustart starten (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung&lt;br /&gt;
(z.B. Einzelsitzung) die &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt;-Zeile weglassen&lt;br /&gt;
und nur &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt; ausführen.  Die&lt;br /&gt;
env-var-Zeile lässt sich ebenfalls weglassen, wenn&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; nur in der aktuellen Shell gebraucht&lt;br /&gt;
wird — dann statt der &amp;lt;code&amp;gt;[Environment]&amp;lt;/code&amp;gt;-Variante&lt;br /&gt;
&amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Auf stark abgespeckten Windows-Installationen ist der&lt;br /&gt;
ssh-agent-Dienst eventuell nicht vorhanden.  Einmalig nachrüsten&lt;br /&gt;
über &#039;&#039;&#039;Einstellungen → Apps → Optionale Features → OpenSSH-&lt;br /&gt;
Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative Agenten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — eigenes Protokoll; von ST/X&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Agent&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; unterstützt.  Schlüssel zu&lt;br /&gt;
OpenSSH migrieren.&lt;br /&gt;
* &#039;&#039;&#039;Git für Windows ssh-agent&#039;&#039;&#039; — funktioniert;&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; auf den dort veröffentlichten Socket&lt;br /&gt;
zeigen lassen.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — ein ST/X innerhalb der WSL sieht den WSL-eigenen&lt;br /&gt;
Agent normal; ein ST/X auf der Windows-Seite nicht.  Eine&lt;br /&gt;
Brücke per &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt; ist&lt;br /&gt;
möglich.&lt;br /&gt;
&lt;br /&gt;
Prüfung über die Settings-Seite&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
die Anzeige dort meldet, ob das laufende Image den Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Windows-OpenSSH speichert agent-geladene Schlüssel &#039;&#039;&#039;nicht&#039;&#039;&#039;&lt;br /&gt;
über Agent-Neustarts hinweg.  Um nicht nach jedem Reboot manuell&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; aufrufen zu müssen, dieselbe Lazy-Load-&lt;br /&gt;
Konfiguration in &amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;&lt;br /&gt;
eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent&lt;br /&gt;
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige&lt;br /&gt;
Sitzung weiter.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Alle Stellschrauben sind klassenseitig auf&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; erreichbar:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Voreinstellung !! Steuert&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 Min) || Wie lange&lt;br /&gt;
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.&lt;br /&gt;
Liegt knapp unter dem typischen&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; des sshd,&lt;br /&gt;
damit wir uns recyceln, bevor der Server uns mit TCP-RESET&lt;br /&gt;
trennt.  &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; setzt auf Voreinstellung zurück.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Maximales Alter (s)&lt;br /&gt;
eines gecachten STAT, bevor &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; neu am&lt;br /&gt;
Server fragt.  Eltern-listDir stempelt ohnehin frische Attribute&lt;br /&gt;
auf alle Kinder, daher zahlt das Navigieren im offenen&lt;br /&gt;
Verzeichnis das TTL nicht.  &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; schaltet den Cache&lt;br /&gt;
ab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (Aktion) || Reißt jede&lt;br /&gt;
gepoolte Verbindung ab.  Nützlich nach einem bekannt schlechten&lt;br /&gt;
Netzereignis, vor einem bewussten Identitätswechsel oder zum&lt;br /&gt;
sauberen Image-Shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnose ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; über das Untermenü „Status&amp;quot; des&lt;br /&gt;
Launchers öffnen.  Der pro-Host-SFTP-Mutex erscheint als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;, der pool-weite Mutex als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Per Rechtsklick:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — schreibt den Walkback&lt;br /&gt;
des letzten Eigners samt aller Waiter als Text in die&lt;br /&gt;
Zwischenablage.  Unverzichtbar, wenn ein Prozess in&lt;br /&gt;
&amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; innerhalb von&lt;br /&gt;
&amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; klemmt.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — die ganze Tabelle, ideal für eine&lt;br /&gt;
E-Mail-Diagnose.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS über den Wait-for-Graph, meldet&lt;br /&gt;
Zyklen.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
Interessante Ereignisse werden über &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; geloggt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei automatischem Reconnect nach toter&lt;br /&gt;
Verbindung.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei Idle-Verdrängung eines Pool-Eintrags.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; wenn eine SSH-Schlüsseldatei nicht&lt;br /&gt;
geparst werden konnte — die Datei wird übersprungen.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nur SFTP v3.&#039;&#039;&#039;  Kein SETSTAT (kein entferntes&lt;br /&gt;
chmod / chown / utime), kein SSH_FXP_READLINK exponiert&lt;br /&gt;
(&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; liefert immer &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; die normale stat-Info).  Einige&lt;br /&gt;
SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische&lt;br /&gt;
SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]] weiter unten.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host.&#039;&#039;&#039;  Zwei gleichzeitige Operationen&lt;br /&gt;
am selben Host stehen am Host-Mutex an.  Siehe [[#Ausblick]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt;-Fallback hat ein TOCTOU-Fenster.&#039;&#039;&#039;&lt;br /&gt;
Bei Servern, die &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; ankündigen&lt;br /&gt;
(jedes moderne OpenSSH tut das), ist das Überschreiben atomar.&lt;br /&gt;
Beim seltenen Server, der das nicht tut, wird auf&lt;br /&gt;
Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich&lt;br /&gt;
dazwischenschieben.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; ist eine Heuristik.&#039;&#039;&#039;&lt;br /&gt;
Liefert immer &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (die genaue Antwort&lt;br /&gt;
würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das&lt;br /&gt;
ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).&lt;br /&gt;
&lt;br /&gt;
== Implementierungsdetails ==&lt;br /&gt;
&lt;br /&gt;
Für Leser, die die Architektur verstehen wollen.  Fünf Klassen,&lt;br /&gt;
von oben nach unten:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Aufgabe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename-Unterklasse, die&lt;br /&gt;
öffentliche API.  Bildet &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt;-URLs auf&lt;br /&gt;
entfernte Dateien ab und stellt &amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; usw. bereit.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3-Protokoll&lt;br /&gt;
(Request/Response-Codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Wird von SftpFilename angesteuert.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH-Kanal-Multiplexer (CHANNEL_OPEN,&lt;br /&gt;
DATA, EOF, CLOSE, WINDOW_ADJUST).  Eine logische Sitzung pro&lt;br /&gt;
Channel-Instanz.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-Level-SSH-Client: öffnet den&lt;br /&gt;
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und&lt;br /&gt;
verteilt anschließend Kanäle.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Drahtschicht.  Banner- und&lt;br /&gt;
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq /&lt;br /&gt;
recvSeq, Heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH-SFTP-Erweiterungen ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst&lt;br /&gt;
minimal gehalten.  OpenSSH bringt einen offenen&lt;br /&gt;
Erweiterungsmechanismus mit: der Server listet im&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;-Reply die Erweiterungsnamen auf, die&lt;br /&gt;
er versteht, und der Client ruft sie über&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt;-Pakete mit dem&lt;br /&gt;
Erweiterungsnamen als erstem String auf.  Jede Erweiterung wird&lt;br /&gt;
über &amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;&lt;br /&gt;
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie&lt;br /&gt;
nicht ankündigt.&lt;br /&gt;
&lt;br /&gt;
Der Stack nutzt heute vier OpenSSH-Erweiterungen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomares&lt;br /&gt;
rename-mit-Überschreiben.  Wird automatisch von&lt;br /&gt;
&amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt; aufgegriffen; die&lt;br /&gt;
Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum&lt;br /&gt;
Einsatz, die die Erweiterung nicht haben.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — Erzeugt einen POSIX-Hardlink.&lt;br /&gt;
Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX-&lt;br /&gt;
&amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-typische Dateisystem-Statistik.&lt;br /&gt;
Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;;&lt;br /&gt;
das Ergebnis ist form-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;, sodass Aufrufer&lt;br /&gt;
lokale und entfernte Pfade einheitlich behandeln können.&lt;br /&gt;
Treibt den Menü-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; an,&lt;br /&gt;
der am Anfang dieser Seite beschrieben ist.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — schreibt den&lt;br /&gt;
serverseitigen Schreibpuffer eines geöffneten Handles auf&lt;br /&gt;
Platte.  Liegt als&lt;br /&gt;
&amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt; bereit; noch nicht&lt;br /&gt;
in eine &amp;quot;Durable-Write&amp;quot;-API auf Filename-Ebene eingebunden.&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden OpenSSH-Erweiterungen&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
werden in der angekündigten Liste erkannt, aber nicht auf&lt;br /&gt;
Filename-Ebene gekapselt — es gibt dafür noch keinen&lt;br /&gt;
Filename-seitigen Aufrufer.&lt;br /&gt;
&lt;br /&gt;
=== Verbindungs-Pooling ===&lt;br /&gt;
&lt;br /&gt;
Alle &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt;-Instanzen, die auf dasselbe Tripel&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; zeigen, teilen sich einen&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; samt einem &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Der Pool ist klassenseitig und wird von einem einzigen&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt; bewacht:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy-Aufbau&#039;&#039;&#039; — TCP + KEX + userauth + SFTP-INIT laufen&lt;br /&gt;
erst beim ersten SFTP-Aufruf, nicht in &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host&#039;&#039;&#039; — SFTP-Anfragen an einen&lt;br /&gt;
bestimmten Host werden durch einen &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt;&lt;br /&gt;
mit dem Namen &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
serialisiert (sichtbar im SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle-Verdrängung&#039;&#039;&#039; — ein Pool-Eintrag, der länger als&lt;br /&gt;
&amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt; ungenutzt liegt, wird beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet.&lt;br /&gt;
* &#039;&#039;&#039;Automatischer Reconnect&#039;&#039;&#039; — ein Fehler auf Transportebene&lt;br /&gt;
(Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den&lt;br /&gt;
Pool-Eintrag, öffnet einen frischen Client und wiederholt die&lt;br /&gt;
Anfrage &#039;&#039;&#039;einmal&#039;&#039;&#039;.  Anwendungsfehler aus&lt;br /&gt;
SFTP-STATUS-Antworten werden sofort durchgereicht.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
&lt;br /&gt;
Geplant, aber noch nicht umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-Channel-Parallelität pro Host&#039;&#039;&#039; — aktuell bedeutet&lt;br /&gt;
eine TCP- plus eine SFTP-Verbindung pro Host, dass N&lt;br /&gt;
gleichzeitige Anfragen serialisieren.  Pipelining über mehrere&lt;br /&gt;
SshClients im Pool (bevorzugt) oder ein transport-seitiger&lt;br /&gt;
Reader-Prozess, der eingehende Pakete in&lt;br /&gt;
Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel&lt;br /&gt;
erlauben, weiter aufzulisten, während das Inhalts-Panel eine&lt;br /&gt;
große Datei liest.&lt;br /&gt;
* &#039;&#039;&#039;Genaues &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR&lt;br /&gt;
+ READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro&lt;br /&gt;
Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen&lt;br /&gt;
kann.&lt;br /&gt;
* &#039;&#039;&#039;SFTP-v5/v6-Aushandlung&#039;&#039;&#039; für erweiterte Attribute und&lt;br /&gt;
FTP-artige Kanonisierung.  (Atomares Überschreibungs-rename&lt;br /&gt;
ist bereits über die OpenSSH-Erweiterung&lt;br /&gt;
&amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; abgedeckt; siehe&lt;br /&gt;
[[#OpenSSH-SFTP-Erweiterungen]].)&lt;br /&gt;
&lt;br /&gt;
= Kommando-Shell =&lt;br /&gt;
&lt;br /&gt;
Lokale Kommando-Shell auf dieser expecco-Maschine.  Typische&lt;br /&gt;
Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm,&lt;br /&gt;
Brücke zwischen entferntem Workflow und lokalem Tool.&lt;br /&gt;
&lt;br /&gt;
Das RemoteAccess-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des&lt;br /&gt;
expecco-Prozesses.  Ausgaben gehen in das expecco-Log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warnung]] &#039;&#039;&#039;Telnet ist ein veraltetes&lt;br /&gt;
Protokoll ohne Verschlüsselung.&#039;&#039;&#039; Passwörter werden im Klartext&lt;br /&gt;
über die Leitung übertragen; jeder im Netzpfad kann sie lesen.&lt;br /&gt;
Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative&lt;br /&gt;
bietet (typisch: alte Industriesteuerungen, Laborgeräte,&lt;br /&gt;
eingebettete Messgeräte ohne SSH-Stack).  Für alles andere&lt;br /&gt;
[[#SSH und SFTP]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Das expecco-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (interne Demo)&lt;br /&gt;
&lt;br /&gt;
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler&lt;br /&gt;
8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für&lt;br /&gt;
Terminal-Optionen.  Verbindungsaufbau zum Ziel-Host:Port; nach&lt;br /&gt;
optionalem In-Band-Login können beide Seiten Daten senden.&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY,&lt;br /&gt;
Agent-Weiterleitung, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks.&lt;br /&gt;
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack&lt;br /&gt;
als HTTPS-Transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Netz]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Vorlage:Languages&amp;diff=31298</id>
		<title>Vorlage:Languages</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Vorlage:Languages&amp;diff=31298"/>
		<updated>2026-05-26T10:22:02Z</updated>

		<summary type="html">&lt;p&gt;Sv: Add /en to the enumerated language subpages (for non-English master pages)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{nmbox&lt;br /&gt;
 | header = &#039;&#039;&#039;[[Project:Language policy|{{Languages/Title|{{SUBPAGENAME}}}}]]&#039;&#039;&#039;&lt;br /&gt;
 | text = &lt;br /&gt;
&#039;&#039;&#039;[[{{{1|:{{NAMESPACE}}:{{BASEPAGENAME}}}}}|{{{label|English}}}]]&#039;&#039;&#039; {{Languages/Lang|af|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ar|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ast|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|az|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bcc|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bg|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|br|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bn|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bs|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ca|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|cs|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|da|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|de|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|diq|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|el|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|en|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|eo|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|es|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fa|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|gl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|gu|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|he|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hu|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hy|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|id|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|io|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|it|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ja|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ka|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|kk|{{{1|}}}|&lt;br /&gt;
}}&amp;lt;span class=&amp;quot;autonym&amp;quot;&amp;gt;{{Languages/Lang|km|{{{1|}}}|&lt;br /&gt;
}}&amp;lt;/span&amp;gt;{{Languages/Lang|ko|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ksh|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|kw|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|la|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|min|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|mk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ml|{{{1|}}}|&lt;br /&gt;
}}&amp;lt;span class=&amp;quot;autonym&amp;quot;&amp;gt;{{Languages/Lang|mr|{{{1|}}}|&lt;br /&gt;
}}&amp;lt;/span&amp;gt;{{Languages/Lang|ms|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|nl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|no|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|oc|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|or|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pt|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pt-br|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ro|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ru|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|si|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sq|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sv|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ta|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|th|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|tr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|uk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|vi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|yi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|yue|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-hans|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-hant|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-tw|{{{1|}}}}}|&lt;br /&gt;
}}&amp;lt;includeonly&amp;gt;{{#if:{{Languages/Lang|af|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ar|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ast|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|az|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bcc|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bg|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|br|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bn|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bs|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ca|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|cs|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|da|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|de|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|diq|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|el|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|en|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|eo|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|es|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fa|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|gl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|gu|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|he|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hu|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hy|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|id|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|io|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|it|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ja|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ka|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|kk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|km|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ko|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ksh|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|kw|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|la|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|min|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|mk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ml|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|mr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ms|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|nl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|no|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|oc|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|or|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pt|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pt-br|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ro|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ru|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|si|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sq|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sv|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ta|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|th|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|tr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|uk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|vi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|yi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|yue|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-hans|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-hant|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-tw|{{{1|}}}}}&lt;br /&gt;
||[[Category:Languages pages without translations]]}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{documentation}}&lt;br /&gt;
[[Category:Exclude in print]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31297</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31297"/>
		<updated>2026-05-26T10:20:13Z</updated>

		<summary type="html">&lt;p&gt;Sv: Use label= for the bold language link (after Template:Languages patch)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access/en|label=English}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure&lt;br /&gt;
  file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation&lt;br /&gt;
  in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on&lt;br /&gt;
  OpenSSL or libssh.  Use this for anything that touches credentials&lt;br /&gt;
  or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine.&lt;br /&gt;
  Used for local-tool integration and for the local end of a remote&lt;br /&gt;
  workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No&lt;br /&gt;
  encryption, passwords on the wire in clear.  Use only when the&lt;br /&gt;
  target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
  &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;&lt;br /&gt;
  subclass that lets the rest of ST/X treat a remote SFTP path the&lt;br /&gt;
  same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation&lt;br /&gt;
  dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a&lt;br /&gt;
  remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote&lt;br /&gt;
  filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of&lt;br /&gt;
  the filesystem holding the currently displayed directory.  Works&lt;br /&gt;
  uniformly for local paths and SFTP paths; for SFTP it requires&lt;br /&gt;
  the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt;&lt;br /&gt;
  extension (every modern OpenSSH does).  Sizes are reported in&lt;br /&gt;
  IEC binary units (MiB, GiB, TiB) — the largest unit yielding a&lt;br /&gt;
  value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039;&lt;br /&gt;
  rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session&lt;br /&gt;
  via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
  &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same&lt;br /&gt;
  but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
  &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt;&lt;br /&gt;
   (or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and&lt;br /&gt;
   also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only;&lt;br /&gt;
   gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file&lt;br /&gt;
  unencrypted (agent-only mode ignores the passphrase, since the&lt;br /&gt;
  OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to&lt;br /&gt;
  &#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by&lt;br /&gt;
  ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
  &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally;&lt;br /&gt;
  a ST/X on the Windows side does not.  Bridging needs a helper&lt;br /&gt;
  like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s&lt;br /&gt;
  walkback plus each waiter&#039;s, formatted as plain text.  Use when&lt;br /&gt;
  a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
  &amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
  request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an&lt;br /&gt;
  email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports&lt;br /&gt;
  cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed&lt;br /&gt;
  (e.g. legacy PEM, encrypted-without-agent) — the file is skipped,&lt;br /&gt;
  others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime),&lt;br /&gt;
  no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
  &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
  stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
  via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
  [[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the&lt;br /&gt;
  same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On&lt;br /&gt;
  servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every&lt;br /&gt;
  modern OpenSSH does), overwrite is atomic; on the rare server&lt;br /&gt;
  that does not, the receiver is emulated as delete-then-rename&lt;br /&gt;
  and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always&lt;br /&gt;
  returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost&lt;br /&gt;
  three round-trips per directory icon, which made the original tree&lt;br /&gt;
  expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic&lt;br /&gt;
  rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
  &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
  fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link.&lt;br /&gt;
  Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
  &amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
  &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
  shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
  so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
  &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
  top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer&lt;br /&gt;
  to disk on an open handle.  Available on the low-level&lt;br /&gt;
  &amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
  into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens&lt;br /&gt;
  on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host&lt;br /&gt;
  are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
  &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
  SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
  &amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
  closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe,&lt;br /&gt;
  EOF, MNU on nil socket) evicts the dead pool entry, opens a&lt;br /&gt;
  fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level&lt;br /&gt;
  SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP +&lt;br /&gt;
  one SFTP channel per host means N concurrent requests&lt;br /&gt;
  serialise.  Pipelining over multiple SshClients in the pool&lt;br /&gt;
  (preferred), or a transport-level reader process demultiplexing&lt;br /&gt;
  to per-channel inboxes, would let the tree pane keep listing&lt;br /&gt;
  while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR&lt;br /&gt;
  + READ_DIR (first batch only) + CLOSE — three RTTs per probe;&lt;br /&gt;
  needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style&lt;br /&gt;
  canonicalisation.  (Atomic-overwrite rename is already handled&lt;br /&gt;
  via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension;&lt;br /&gt;
  see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent&lt;br /&gt;
  forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of&lt;br /&gt;
  this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack&lt;br /&gt;
  for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31296</id>
		<title>Remote Access</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access&amp;diff=31296"/>
		<updated>2026-05-26T10:20:11Z</updated>

		<summary type="html">&lt;p&gt;Sv: Use label= for the bold language link (after Template:Languages patch)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|label=Deutsch}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fernzugriff&#039;&#039;&#039; bezeichnet die Möglichkeit, einen entfernten&lt;br /&gt;
Rechner oder ein entferntes Netzwerk aus diesem expecco-Image heraus&lt;br /&gt;
zu bedienen — Shells zu öffnen, Befehle abzusetzen, Dateien zu&lt;br /&gt;
verschieben oder ein Testgerät anzusteuern.  Drei Protokoll-Familien&lt;br /&gt;
sind unterstützt, in absteigender Empfehlungsreihenfolge:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH und SFTP&#039;&#039;&#039; (empfohlen) — verschlüsselte Shell und sichere&lt;br /&gt;
  Dateiübertragung über einen SSH-2-Tunnel.  Reine&lt;br /&gt;
  Smalltalk-Implementierung in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;;&lt;br /&gt;
  keine externe Abhängigkeit von OpenSSL oder libssh.  Für alles&lt;br /&gt;
  mit Zugangsdaten oder sensiblen Nutzdaten.&lt;br /&gt;
* &#039;&#039;&#039;Lokale Kommando-Shell&#039;&#039;&#039; — fork + exec auf der lokalen&lt;br /&gt;
  Maschine.  Für die Anbindung lokaler Werkzeuge und für die&lt;br /&gt;
  lokale Seite eines hybriden Workflows.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (veraltet) — Klartext-Terminalsitzung.  Keine&lt;br /&gt;
  Verschlüsselung, Passwörter im Klartext auf der Leitung.  Nur&lt;br /&gt;
  einsetzen, wenn die Gegenstelle keine Alternative bietet.&lt;br /&gt;
&lt;br /&gt;
= SSH und SFTP =&lt;br /&gt;
&lt;br /&gt;
Der SSH-Stack deckt das vollständige SSH-2-Protokoll ab&lt;br /&gt;
(RFC 4251–4254, RFC 5656, RFC 8709, RFC 8731) inklusive der&lt;br /&gt;
chacha20-poly1305-Transportchiffrierung von OpenSSH sowie das&lt;br /&gt;
SFTP-v3-Subsystem (draft-ietf-secsh-filexfer-02).  Zwei Schichten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatischer SSH-Zugriff&lt;br /&gt;
  (entferntes &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY-Shell, Agent-Weiterleitung,&lt;br /&gt;
  ProxyJump-Bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — eine&lt;br /&gt;
  &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;-Unterklasse, die es dem restlichen ST/X&lt;br /&gt;
  erlaubt, einen entfernten SFTP-Pfad zu behandeln wie eine lokale&lt;br /&gt;
  Datei.&lt;br /&gt;
&lt;br /&gt;
Die folgenden Abschnitte sind nutzeraufgaben-zuerst aufgebaut:&lt;br /&gt;
zuerst das, was der Anwender sieht und tut, darunter die&lt;br /&gt;
expecco-Bibliotheks-Anbindung, ganz unten Implementierungsdetails&lt;br /&gt;
für Interessierte.&lt;br /&gt;
&lt;br /&gt;
== Aus dem FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Im Adress-Dropdown eine &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt;-URL einfügen.  Der&lt;br /&gt;
Browser-Tab füllt sich wie bei einem lokalen Pfad.&lt;br /&gt;
Baum-Ausklappen, Spaltensortierung (Name / Größe / mtime),&lt;br /&gt;
Vorschau und Doppelklick zum Öffnen im Editor verhalten sich&lt;br /&gt;
normal.  Der erste Klick auf einen Host dauert ~200–500 ms&lt;br /&gt;
(TCP + KEX + Auth); folgende Klicks nutzen die gepoolte&lt;br /&gt;
Verbindung weiter.&lt;br /&gt;
&lt;br /&gt;
URL-Syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlt &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;, wird der lokale Login-Name verwendet, Port&lt;br /&gt;
ist standardmäßig 22, Pfad standardmäßig &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Menü &#039;&#039;&#039;Tools&#039;&#039;&#039; im FileBrowserV2 bietet vier Aktionen — die&lt;br /&gt;
drei SSH-spezifischen sind nur bei geladener SSH-Bibliothek&lt;br /&gt;
sichtbar:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — öffnet den&lt;br /&gt;
  Schlüsselerzeugungs-Dialog, siehe&lt;br /&gt;
  [[#Einen SSH-Schlüssel erzeugen]] unten.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — öffnet ein interaktives VT100-Terminal&lt;br /&gt;
  zu einem entfernten Host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — navigiert diesen Browser-Tab über SFTP&lt;br /&gt;
  auf ein entferntes Dateisystem.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — zeigt Größe, freien Platz und Belegung&lt;br /&gt;
  des Dateisystems, das das aktuell angezeigte Verzeichnis enthält.&lt;br /&gt;
  Funktioniert einheitlich für lokale und SFTP-Pfade; bei SFTP&lt;br /&gt;
  setzt der Aufruf voraus, daß der Server die Erweiterung&lt;br /&gt;
  &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; ankündigt (jedes moderne OpenSSH&lt;br /&gt;
  tut das).  Größen werden in IEC-Binäreinheiten ausgegeben (MiB,&lt;br /&gt;
  GiB, TiB) — gewählt wird die größte Einheit, die einen Wert ≥ 1&lt;br /&gt;
  liefert, damit ein TB-großes Volume als &#039;&#039;X TiB&#039;&#039; statt&lt;br /&gt;
  &#039;&#039;10240 GiB&#039;&#039; erscheint.&lt;br /&gt;
&lt;br /&gt;
== Aus expecco-Aktionen ==&lt;br /&gt;
&lt;br /&gt;
Das Expecco-RemoteAccess-Plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) stellt folgende Testaktionen&lt;br /&gt;
in der expecco-Aktionspalette bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — öffnet eine&lt;br /&gt;
  SSH-Sitzung über das plattformeigene &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt;-Binary&lt;br /&gt;
  (PuTTYs &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; unter Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; —&lt;br /&gt;
  dasselbe, jedoch mit expliziter Public-Key-Authentifizierung.&lt;br /&gt;
&lt;br /&gt;
Voraussetzung: ein eingerichtetes Schlüsselpaar (privater&lt;br /&gt;
Schlüssel auf dieser Maschine, öffentlicher Teil in der&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des Zielhosts).  Schlüssel&lt;br /&gt;
erzeugen entweder über den Dialog unten oder über&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Das Plugin fügt zusätzlich eine Settings-Seite hinzu:&lt;br /&gt;
&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039; mit&lt;br /&gt;
einer einzelnen Schaltfläche &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039;, die&lt;br /&gt;
denselben Dialog öffnet.&lt;br /&gt;
&lt;br /&gt;
== Einen SSH-Schlüssel erzeugen ==&lt;br /&gt;
&lt;br /&gt;
=== Der Dialog (FileBrowserV2 / Settings-Seite) ===&lt;br /&gt;
&lt;br /&gt;
Der Dialog fragt alle Parameter in einem Formular ab:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — wird in den erzeugten Schlüssel eingebettet&lt;br /&gt;
  (Voreinstellung &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — schreibt&lt;br /&gt;
   &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt; (oder wohin man will) samt&lt;br /&gt;
   zugehöriger &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;-Datei daneben.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — schreibt die Datei&lt;br /&gt;
   UND übergibt den Schlüssel dem laufenden ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — der Schlüssel lebt nur im&lt;br /&gt;
   Speicher des Agents; nach Agent-Neustart ist er verloren.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — vollständiger Pfad; ausgegraut im&lt;br /&gt;
  Agent-only-Modus.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — leer lässt die On-Disk-Datei&lt;br /&gt;
  unverschlüsselt (Agent-only-Modus ignoriert die Passphrase, da&lt;br /&gt;
  das OpenSSH-Agent-Wire-Protokoll nur den entschlüsselten&lt;br /&gt;
  Schlüssel transportiert).&lt;br /&gt;
&lt;br /&gt;
Bei &#039;&#039;&#039;Generate&#039;&#039;&#039; wird die Public-Key-Zeile (dieselbe&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt;-Zeichenfolge, die&lt;br /&gt;
ssh-keygen ausgibt) in die System-Zwischenablage kopiert — zum&lt;br /&gt;
direkten Einfügen in die &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt; des&lt;br /&gt;
Zielhosts.&lt;br /&gt;
&lt;br /&gt;
=== Aus einem Workspace ===&lt;br /&gt;
&lt;br /&gt;
Für Headless-Deployments, Sandbox-Builds oder Skripte stellt&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; einen reinen Smalltalk-Schlüsselgenerator&lt;br /&gt;
bereit, dessen Ausgabe bit-kompatibel zu&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt; ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Passphrase-verschlüsselt auf Platte speichern&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ UND in den laufenden Agent laden&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Public-Key-Zeile zum Einfügen in authorized_keys ausgeben&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die so erzeugten Schlüssel sind mit den OpenSSH-Werkzeugen voll&lt;br /&gt;
interoperabel (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; rekonstruiert den&lt;br /&gt;
öffentlichen Schlüssel, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; ändert&lt;br /&gt;
die Passphrase usw.).&lt;br /&gt;
&lt;br /&gt;
=== Mit den Shell-Werkzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der klassische Weg funktioniert weiterhin:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ssh-agent vorbereiten ==&lt;br /&gt;
&lt;br /&gt;
Der Weg über den Agent ist dem direkten Lesen von Schlüsseldateien&lt;br /&gt;
deutlich vorzuziehen: er hält verschlüsselte private Schlüssel&lt;br /&gt;
einmal pro Sitzung entsperrt und kann Identitäten verwalten&lt;br /&gt;
(hardware-tokengestützte Schlüssel, KeePassXC-Einträge), die ST/X&lt;br /&gt;
nie direkt sehen soll.&lt;br /&gt;
&lt;br /&gt;
ST/X erkennt den Agent-Pfad automatisch, sobald&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;zum Zeitpunkt des Starts von stx&#039;&#039;&#039;&lt;br /&gt;
in der Prozessumgebung gesetzt ist.  Eine spätere Zuweisung aus&lt;br /&gt;
einem Workspace nützt nichts.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Die meisten Desktop-Distributionen starten einen Agent automatisch&lt;br /&gt;
beim Login (gnome-keyring unter GNOME, ssh-agent.service unter&lt;br /&gt;
systemd, KWallet unter KDE).  Prüfen im Terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh oder ähnlich&lt;br /&gt;
ssh-add -l             # listet geladene Identitäten&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # eigene laden, falls nicht da&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Läuft gar kein Agent, dieses Snippet in die Shell-rc-Datei&lt;br /&gt;
aufnehmen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc oder ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X muss aus einer Shell gestartet werden, die diese rc bereits&lt;br /&gt;
gelesen hat — ein Desktop-Launcher aus dem Dateimanager erbt die&lt;br /&gt;
Variable nicht.  Empfehlung: ein kleines Wrapper-Skript unter&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt;, das die rc sourcet und dann stx&lt;br /&gt;
startet.&lt;br /&gt;
&lt;br /&gt;
Die Settings-Seite (&#039;&#039;&#039;Extras → Settings → Plugins → Remote&lt;br /&gt;
Access — SSH Keys&#039;&#039;&#039;) zeigt an, ob das laufende Image einen&lt;br /&gt;
Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Permanente Einrichtung via systemd ====&lt;br /&gt;
&lt;br /&gt;
Für einen wirklich sitzungsübergreifenden Agent (überlebt Desktop-&lt;br /&gt;
Abmeldung, kommt beim nächsten Login wieder hoch) die bei den&lt;br /&gt;
meisten Distros mit dem Paket &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
ausgelieferte Per-User-systemd-Unit aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; in der Shell-rc auf den&lt;br /&gt;
User-Service-Socket zeigen lassen (ersetzt das&lt;br /&gt;
&amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;-Snippet oben):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Um den manuellen &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt;-Schritt zu sparen, kann&lt;br /&gt;
OpenSSH Schlüssel beim ersten Bedarf selbst in den Agent laden.&lt;br /&gt;
In &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt; eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste SSH-Verbindung fragt dann einmal nach der Passphrase und&lt;br /&gt;
übergibt den entsperrten Schlüssel an den Agent; weitere&lt;br /&gt;
Verbindungen nutzen die gespeicherte Identität ohne Prompt.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ bringt das native OpenSSH inklusive Agent-Dienst mit.&lt;br /&gt;
Einmalige Einrichtung:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Dienste&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) als Administrator öffnen.&lt;br /&gt;
# &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039; suchen, Starttyp auf&lt;br /&gt;
  &#039;&#039;&#039;Automatisch&#039;&#039;&#039; setzen, &#039;&#039;&#039;Starten&#039;&#039;&#039; anklicken.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Prüfen: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Der Windows-OpenSSH-Agent lauscht auf einer Named Pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), nicht auf einem&lt;br /&gt;
Unix-Socket.  ST/X unterstützt beide Transporte, jedoch setzt das&lt;br /&gt;
Windows-ssh-add &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; selbst.&lt;br /&gt;
Daher einmalig systemweit setzen:&lt;br /&gt;
&lt;br /&gt;
# {{Key|Win}} drücken → &amp;quot;Umgebungsvariablen&amp;quot; → „Systemumgebungs-&lt;br /&gt;
  variablen bearbeiten&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Umgebungsvariablen&#039;&#039;&#039; → unter &#039;&#039;&#039;Benutzervariablen&#039;&#039;&#039;,&lt;br /&gt;
  &#039;&#039;&#039;Neu&#039;&#039;&#039; klicken.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Wert: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Ab- und wieder anmelden (oder stx neu starten), damit die neue&lt;br /&gt;
  Umgebung übernommen wird.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell-Schnelleinrichtung ====&lt;br /&gt;
&lt;br /&gt;
Derselbe Aufbau aus einer &#039;&#039;&#039;Administrator-PowerShell&#039;&#039;&#039; heraus,&lt;br /&gt;
z.B. für Skripte oder unbeaufsichtigte Bereitstellung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Agent jetzt und bei jedem Neustart starten (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# SSH_AUTH_SOCK dauerhaft für den Benutzer setzen (übersteht Reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Schlüssel laden (fragt nach Passphrase, falls die Datei verschlüsselt ist).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für einen einmaligen Agent-Start ohne dauerhafte Aktivierung&lt;br /&gt;
(z.B. Einzelsitzung) die &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt;-Zeile weglassen&lt;br /&gt;
und nur &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt; ausführen.  Die&lt;br /&gt;
env-var-Zeile lässt sich ebenfalls weglassen, wenn&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; nur in der aktuellen Shell gebraucht&lt;br /&gt;
wird — dann statt der &amp;lt;code&amp;gt;[Environment]&amp;lt;/code&amp;gt;-Variante&lt;br /&gt;
&amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Auf stark abgespeckten Windows-Installationen ist der&lt;br /&gt;
ssh-agent-Dienst eventuell nicht vorhanden.  Einmalig nachrüsten&lt;br /&gt;
über &#039;&#039;&#039;Einstellungen → Apps → Optionale Features → OpenSSH-&lt;br /&gt;
Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative Agenten:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — eigenes Protokoll; von ST/X&#039;s&lt;br /&gt;
  &amp;lt;code&amp;gt;SSH::Agent&amp;lt;/code&amp;gt; &#039;&#039;&#039;nicht&#039;&#039;&#039; unterstützt.  Schlüssel zu&lt;br /&gt;
  OpenSSH migrieren.&lt;br /&gt;
* &#039;&#039;&#039;Git für Windows ssh-agent&#039;&#039;&#039; — funktioniert;&lt;br /&gt;
  &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; auf den dort veröffentlichten Socket&lt;br /&gt;
  zeigen lassen.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — ein ST/X innerhalb der WSL sieht den WSL-eigenen&lt;br /&gt;
  Agent normal; ein ST/X auf der Windows-Seite nicht.  Eine&lt;br /&gt;
  Brücke per &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt; ist&lt;br /&gt;
  möglich.&lt;br /&gt;
&lt;br /&gt;
Prüfung über die Settings-Seite&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
die Anzeige dort meldet, ob das laufende Image den Agent sieht.&lt;br /&gt;
&lt;br /&gt;
==== Schlüssel automatisch beim ersten Einsatz laden ====&lt;br /&gt;
&lt;br /&gt;
Windows-OpenSSH speichert agent-geladene Schlüssel &#039;&#039;&#039;nicht&#039;&#039;&#039;&lt;br /&gt;
über Agent-Neustarts hinweg.  Um nicht nach jedem Reboot manuell&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; aufrufen zu müssen, dieselbe Lazy-Load-&lt;br /&gt;
Konfiguration in &amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;&lt;br /&gt;
eintragen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH lädt den Schlüssel dann beim ersten Einsatz in den Agent&lt;br /&gt;
(fragt einmal nach der Passphrase) und nutzt ihn für die übrige&lt;br /&gt;
Sitzung weiter.&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Alle Stellschrauben sind klassenseitig auf&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; erreichbar:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Voreinstellung !! Steuert&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 Min) || Wie lange&lt;br /&gt;
eine gepoolte Verbindung im Leerlauf liegen darf, bevor sie beim&lt;br /&gt;
nächsten Zugriff proaktiv geschlossen und neu geöffnet wird.&lt;br /&gt;
Liegt knapp unter dem typischen&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; des sshd,&lt;br /&gt;
damit wir uns recyceln, bevor der Server uns mit TCP-RESET&lt;br /&gt;
trennt.  &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; setzt auf Voreinstellung zurück.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Maximales Alter (s)&lt;br /&gt;
eines gecachten STAT, bevor &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; neu am&lt;br /&gt;
Server fragt.  Eltern-listDir stempelt ohnehin frische Attribute&lt;br /&gt;
auf alle Kinder, daher zahlt das Navigieren im offenen&lt;br /&gt;
Verzeichnis das TTL nicht.  &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; schaltet den Cache&lt;br /&gt;
ab.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (Aktion) || Reißt jede&lt;br /&gt;
gepoolte Verbindung ab.  Nützlich nach einem bekannt schlechten&lt;br /&gt;
Netzereignis, vor einem bewussten Identitätswechsel oder zum&lt;br /&gt;
sauberen Image-Shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnose ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; über das Untermenü „Status&amp;quot; des&lt;br /&gt;
Launchers öffnen.  Der pro-Host-SFTP-Mutex erscheint als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;, der pool-weite Mutex als&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Per Rechtsklick:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — schreibt den Walkback&lt;br /&gt;
  des letzten Eigners samt aller Waiter als Text in die&lt;br /&gt;
  Zwischenablage.  Unverzichtbar, wenn ein Prozess in&lt;br /&gt;
  &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; innerhalb von&lt;br /&gt;
  &amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; klemmt.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — die ganze Tabelle, ideal für eine&lt;br /&gt;
  E-Mail-Diagnose.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS über den Wait-for-Graph, meldet&lt;br /&gt;
  Zyklen.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
Interessante Ereignisse werden über &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; geloggt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei automatischem Reconnect nach toter&lt;br /&gt;
  Verbindung.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; bei Idle-Verdrängung eines Pool-Eintrags.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; wenn eine SSH-Schlüsseldatei nicht&lt;br /&gt;
  geparst werden konnte — die Datei wird übersprungen.&lt;br /&gt;
&lt;br /&gt;
== Einschränkungen ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Nur SFTP v3.&#039;&#039;&#039;  Kein SETSTAT (kein entferntes&lt;br /&gt;
  chmod / chown / utime), kein SSH_FXP_READLINK exponiert&lt;br /&gt;
  (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; liefert immer &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;,&lt;br /&gt;
  &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; die normale stat-Info).  Einige&lt;br /&gt;
  SFTPv5+-Annehmlichkeiten werden dennoch über OpenSSH-spezifische&lt;br /&gt;
  SSH_FXP_EXTENDED-Aufrufe nutzbar — siehe&lt;br /&gt;
  [[#OpenSSH-SFTP-Erweiterungen]] weiter unten.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host.&#039;&#039;&#039;  Zwei gleichzeitige Operationen&lt;br /&gt;
  am selben Host stehen am Host-Mutex an.  Siehe [[#Ausblick]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt;-Fallback hat ein TOCTOU-Fenster.&#039;&#039;&#039;&lt;br /&gt;
  Bei Servern, die &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; ankündigen&lt;br /&gt;
  (jedes moderne OpenSSH tut das), ist das Überschreiben atomar.&lt;br /&gt;
  Beim seltenen Server, der das nicht tut, wird auf&lt;br /&gt;
  Delete-dann-Rename ausgewichen und ein anderer Prozess kann sich&lt;br /&gt;
  dazwischenschieben.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; ist eine Heuristik.&#039;&#039;&#039;&lt;br /&gt;
  Liefert immer &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (die genaue Antwort&lt;br /&gt;
  würde drei Roundtrips pro Verzeichnis-Symbol kosten, was das&lt;br /&gt;
  ursprüngliche Baum-Ausklappen unerträglich gebremst hatte).&lt;br /&gt;
&lt;br /&gt;
== Implementierungsdetails ==&lt;br /&gt;
&lt;br /&gt;
Für Leser, die die Architektur verstehen wollen.  Fünf Klassen,&lt;br /&gt;
von oben nach unten:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klasse !! Aufgabe&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename-Unterklasse, die&lt;br /&gt;
öffentliche API.  Bildet &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt;-URLs auf&lt;br /&gt;
entfernte Dateien ab und stellt &amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; usw. bereit.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3-Protokoll&lt;br /&gt;
(Request/Response-Codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Wird von SftpFilename angesteuert.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH-Kanal-Multiplexer (CHANNEL_OPEN,&lt;br /&gt;
DATA, EOF, CLOSE, WINDOW_ADJUST).  Eine logische Sitzung pro&lt;br /&gt;
Channel-Instanz.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-Level-SSH-Client: öffnet den&lt;br /&gt;
Transport, führt KEX, Hostschlüssel-Prüfung und userauth durch und&lt;br /&gt;
verteilt anschließend Kanäle.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Drahtschicht.  Banner- und&lt;br /&gt;
KEXINIT-Austausch, ChaCha20-Poly1305-Paket-Framing, sendSeq /&lt;br /&gt;
recvSeq, Heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH-SFTP-Erweiterungen ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (Entwurf draft-ietf-secsh-filexfer-02) ist bewusst&lt;br /&gt;
minimal gehalten.  OpenSSH bringt einen offenen&lt;br /&gt;
Erweiterungsmechanismus mit: der Server listet im&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;-Reply die Erweiterungsnamen auf, die&lt;br /&gt;
er versteht, und der Client ruft sie über&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt;-Pakete mit dem&lt;br /&gt;
Erweiterungsnamen als erstem String auf.  Jede Erweiterung wird&lt;br /&gt;
über &amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;&lt;br /&gt;
feature-detektiert; Aufrufer fallen zurück, wenn der Server sie&lt;br /&gt;
nicht ankündigt.&lt;br /&gt;
&lt;br /&gt;
Der Stack nutzt heute vier OpenSSH-Erweiterungen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomares&lt;br /&gt;
  rename-mit-Überschreiben.  Wird automatisch von&lt;br /&gt;
  &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt; aufgegriffen; die&lt;br /&gt;
  Delete-dann-Rename-Fallback-Variante kommt nur bei Servern zum&lt;br /&gt;
  Einsatz, die die Erweiterung nicht haben.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — Erzeugt einen POSIX-Hardlink.&lt;br /&gt;
  Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX-&lt;br /&gt;
  &amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-typische Dateisystem-Statistik.&lt;br /&gt;
  Verfügbar als &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;;&lt;br /&gt;
  das Ergebnis ist form-kompatibel zu&lt;br /&gt;
  &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;, sodass Aufrufer&lt;br /&gt;
  lokale und entfernte Pfade einheitlich behandeln können.&lt;br /&gt;
  Treibt den Menü-Eintrag &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; an,&lt;br /&gt;
  der am Anfang dieser Seite beschrieben ist.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — schreibt den&lt;br /&gt;
  serverseitigen Schreibpuffer eines geöffneten Handles auf&lt;br /&gt;
  Platte.  Liegt als&lt;br /&gt;
  &amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt; bereit; noch nicht&lt;br /&gt;
  in eine &amp;quot;Durable-Write&amp;quot;-API auf Filename-Ebene eingebunden.&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden OpenSSH-Erweiterungen&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
werden in der angekündigten Liste erkannt, aber nicht auf&lt;br /&gt;
Filename-Ebene gekapselt — es gibt dafür noch keinen&lt;br /&gt;
Filename-seitigen Aufrufer.&lt;br /&gt;
&lt;br /&gt;
=== Verbindungs-Pooling ===&lt;br /&gt;
&lt;br /&gt;
Alle &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt;-Instanzen, die auf dasselbe Tripel&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; zeigen, teilen sich einen&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; samt einem &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Der Pool ist klassenseitig und wird von einem einzigen&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt; bewacht:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy-Aufbau&#039;&#039;&#039; — TCP + KEX + userauth + SFTP-INIT laufen&lt;br /&gt;
  erst beim ersten SFTP-Aufruf, nicht in &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Serialisierung pro Host&#039;&#039;&#039; — SFTP-Anfragen an einen&lt;br /&gt;
  bestimmten Host werden durch einen &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt;&lt;br /&gt;
  mit dem Namen &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
  serialisiert (sichtbar im SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle-Verdrängung&#039;&#039;&#039; — ein Pool-Eintrag, der länger als&lt;br /&gt;
  &amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt; ungenutzt liegt, wird beim&lt;br /&gt;
  nächsten Zugriff proaktiv geschlossen und neu geöffnet.&lt;br /&gt;
* &#039;&#039;&#039;Automatischer Reconnect&#039;&#039;&#039; — ein Fehler auf Transportebene&lt;br /&gt;
  (Broken Pipe, EOF, MNU auf nil-Socket) verdrängt den&lt;br /&gt;
  Pool-Eintrag, öffnet einen frischen Client und wiederholt die&lt;br /&gt;
  Anfrage &#039;&#039;&#039;einmal&#039;&#039;&#039;.  Anwendungsfehler aus&lt;br /&gt;
  SFTP-STATUS-Antworten werden sofort durchgereicht.&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
&lt;br /&gt;
Geplant, aber noch nicht umgesetzt:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-Channel-Parallelität pro Host&#039;&#039;&#039; — aktuell bedeutet&lt;br /&gt;
  eine TCP- plus eine SFTP-Verbindung pro Host, dass N&lt;br /&gt;
  gleichzeitige Anfragen serialisieren.  Pipelining über mehrere&lt;br /&gt;
  SshClients im Pool (bevorzugt) oder ein transport-seitiger&lt;br /&gt;
  Reader-Prozess, der eingehende Pakete in&lt;br /&gt;
  Pro-Kanal-Postfächer demultiplext, würde es dem Baum-Panel&lt;br /&gt;
  erlauben, weiter aufzulisten, während das Inhalts-Panel eine&lt;br /&gt;
  große Datei liest.&lt;br /&gt;
* &#039;&#039;&#039;Genaues &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR&lt;br /&gt;
  + READ_DIR (nur erstes Batch) + CLOSE — drei Roundtrips pro&lt;br /&gt;
  Sondierung; lohnt erst, wenn der SftpClient Anfragen pipelinen&lt;br /&gt;
  kann.&lt;br /&gt;
* &#039;&#039;&#039;SFTP-v5/v6-Aushandlung&#039;&#039;&#039; für erweiterte Attribute und&lt;br /&gt;
  FTP-artige Kanonisierung.  (Atomares Überschreibungs-rename&lt;br /&gt;
  ist bereits über die OpenSSH-Erweiterung&lt;br /&gt;
  &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; abgedeckt; siehe&lt;br /&gt;
  [[#OpenSSH-SFTP-Erweiterungen]].)&lt;br /&gt;
&lt;br /&gt;
= Kommando-Shell =&lt;br /&gt;
&lt;br /&gt;
Lokale Kommando-Shell auf dieser expecco-Maschine.  Typische&lt;br /&gt;
Anwendungen: lokale Kommandozeile, lokales Hilfsprogramm,&lt;br /&gt;
Brücke zwischen entferntem Workflow und lokalem Tool.&lt;br /&gt;
&lt;br /&gt;
Das RemoteAccess-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Keine Zugangsdaten, kein Netzwerk — läuft als der Benutzer des&lt;br /&gt;
expecco-Prozesses.  Ausgaben gehen in das expecco-Log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warnung]] &#039;&#039;&#039;Telnet ist ein veraltetes&lt;br /&gt;
Protokoll ohne Verschlüsselung.&#039;&#039;&#039; Passwörter werden im Klartext&lt;br /&gt;
über die Leitung übertragen; jeder im Netzpfad kann sie lesen.&lt;br /&gt;
Telnet NUR einsetzen, wenn die Gegenstelle keine Alternative&lt;br /&gt;
bietet (typisch: alte Industriesteuerungen, Laborgeräte,&lt;br /&gt;
eingebettete Messgeräte ohne SSH-Stack).  Für alles andere&lt;br /&gt;
[[#SSH und SFTP]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Das expecco-Plugin stellt bereit:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (interne Demo)&lt;br /&gt;
&lt;br /&gt;
Das Telnet-Protokoll (RFC 854) ist ein bidirektionaler&lt;br /&gt;
8-Bit-Byte-Strom über TCP, mit In-Band-Steuersequenzen für&lt;br /&gt;
Terminal-Optionen.  Verbindungsaufbau zum Ziel-Host:Port; nach&lt;br /&gt;
optionalem In-Band-Login können beide Seiten Daten senden.&lt;br /&gt;
&lt;br /&gt;
= Siehe auch =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client|SSH::Client]] — die SSH-Schicht (exec, TTY,&lt;br /&gt;
  Agent-Weiterleitung, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2]] — die Haupt-UI dieses Stacks.&lt;br /&gt;
* [[ClaudeCode plugin|Claude Code]] — nutzt denselben SSH-Stack&lt;br /&gt;
  als HTTPS-Transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Netz]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Vorlage:Languages&amp;diff=31295</id>
		<title>Vorlage:Languages</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Vorlage:Languages&amp;diff=31295"/>
		<updated>2026-05-26T10:19:27Z</updated>

		<summary type="html">&lt;p&gt;Sv: Make bold-link label parameterizable (default English) — see Talk for rationale&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{nmbox&lt;br /&gt;
 | header = &#039;&#039;&#039;[[Project:Language policy|{{Languages/Title|{{SUBPAGENAME}}}}]]&#039;&#039;&#039;&lt;br /&gt;
 | text = &lt;br /&gt;
&#039;&#039;&#039;[[{{{1|:{{NAMESPACE}}:{{BASEPAGENAME}}}}}|{{{label|English}}}]]&#039;&#039;&#039; {{Languages/Lang|af|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ar|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ast|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|az|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bcc|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bg|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|br|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bn|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bs|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ca|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|cs|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|da|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|de|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|diq|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|el|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|eo|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|es|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fa|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|gl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|gu|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|he|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hu|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hy|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|id|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|io|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|it|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ja|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ka|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|kk|{{{1|}}}|&lt;br /&gt;
}}&amp;lt;span class=&amp;quot;autonym&amp;quot;&amp;gt;{{Languages/Lang|km|{{{1|}}}|&lt;br /&gt;
}}&amp;lt;/span&amp;gt;{{Languages/Lang|ko|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ksh|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|kw|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|la|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|min|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|mk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ml|{{{1|}}}|&lt;br /&gt;
}}&amp;lt;span class=&amp;quot;autonym&amp;quot;&amp;gt;{{Languages/Lang|mr|{{{1|}}}|&lt;br /&gt;
}}&amp;lt;/span&amp;gt;{{Languages/Lang|ms|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|nl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|no|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|oc|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|or|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pt|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pt-br|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ro|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ru|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|si|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sq|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sv|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ta|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|th|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|tr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|uk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|vi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|yi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|yue|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-hans|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-hant|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-tw|{{{1|}}}}}|&lt;br /&gt;
}}&amp;lt;includeonly&amp;gt;{{#if:{{Languages/Lang|af|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ar|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ast|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|az|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bcc|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bg|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|br|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bn|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|bs|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ca|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|cs|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|da|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|de|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|diq|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|el|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|eo|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|es|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fa|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|fr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|gl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|gu|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|he|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hu|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|hy|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|id|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|io|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|it|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ja|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ka|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|kk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|km|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ko|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ksh|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|kw|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|la|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|min|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|mk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ml|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|mr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ms|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|nl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|no|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|oc|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|or|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pt|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|pt-br|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ro|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ru|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|si|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sl|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sq|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|sv|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|ta|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|th|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|tr|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|uk|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|vi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|yi|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|yue|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-hans|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-hant|{{{1|}}}|&lt;br /&gt;
}}{{Languages/Lang|zh-tw|{{{1|}}}}}&lt;br /&gt;
||[[Category:Languages pages without translations]]}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{documentation}}&lt;br /&gt;
[[Category:Exclude in print]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
	<entry>
		<id>https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31294</id>
		<title>Remote Access/en</title>
		<link rel="alternate" type="text/html" href="https://doc.expecco.de/index.php?title=Remote_Access/en&amp;diff=31294"/>
		<updated>2026-05-26T09:53:07Z</updated>

		<summary type="html">&lt;p&gt;Sv: Add Filesystem Info feature; document OpenSSH SFTP extensions (posix-rename, hardlink, statvfs, fsync); correct stale limitations/future-work entries.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|Remote Access|Remote Access/en}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Remote access&#039;&#039;&#039; is the ability to drive a remote computer or&lt;br /&gt;
network from this expecco image — opening shells, running commands,&lt;br /&gt;
moving files, or driving a test target.  Three protocol families are&lt;br /&gt;
supported, listed in current-recommended order:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SSH and SFTP&#039;&#039;&#039; (recommended) — encrypted shell + secure&lt;br /&gt;
  file transfer over an SSH-2 tunnel.  Pure-Smalltalk implementation&lt;br /&gt;
  in &amp;lt;code&amp;gt;exept:libcrypt/ssh&amp;lt;/code&amp;gt;; no external dependency on&lt;br /&gt;
  OpenSSL or libssh.  Use this for anything that touches credentials&lt;br /&gt;
  or sensitive payloads.&lt;br /&gt;
* &#039;&#039;&#039;Local Command Shell&#039;&#039;&#039; — fork + exec on the local machine.&lt;br /&gt;
  Used for local-tool integration and for the local end of a remote&lt;br /&gt;
  workflow that bridges via another protocol.&lt;br /&gt;
* &#039;&#039;&#039;Telnet&#039;&#039;&#039; (legacy) — plain-text terminal session.  No&lt;br /&gt;
  encryption, passwords on the wire in clear.  Use only when the&lt;br /&gt;
  target hardware has no other option.&lt;br /&gt;
&lt;br /&gt;
= SSH and SFTP =&lt;br /&gt;
&lt;br /&gt;
The SSH stack covers the full SSH-2 protocol (RFC 4251–4254,&lt;br /&gt;
RFC 5656, RFC 8709, RFC 8731) plus OpenSSH&#039;s chacha20-poly1305&lt;br /&gt;
transport cipher and the SFTP v3 file-transfer subsystem&lt;br /&gt;
(draft-ietf-secsh-filexfer-02).  Two layers:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt;&#039;&#039;&#039; — programmatic SSH access (remote&lt;br /&gt;
  &amp;lt;code&amp;gt;exec&amp;lt;/code&amp;gt;, TTY shell, agent forwarding, ProxyJump bastion).&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;&#039;&#039;&#039; — a &amp;lt;code&amp;gt;Filename&amp;lt;/code&amp;gt;&lt;br /&gt;
  subclass that lets the rest of ST/X treat a remote SFTP path the&lt;br /&gt;
  same way it treats a local file.&lt;br /&gt;
&lt;br /&gt;
The rest of this section is organised user-task-first: what the user&lt;br /&gt;
sees and does, the expecco-library hooks below that, then the&lt;br /&gt;
implementation detail at the end for the curious.&lt;br /&gt;
&lt;br /&gt;
== From the FileBrowserV2 ==&lt;br /&gt;
&lt;br /&gt;
Open the location dropdown and paste an &amp;lt;code&amp;gt;sftp://&amp;lt;/code&amp;gt; URL.&lt;br /&gt;
The browser tab populates as if it were a local path.  Tree&lt;br /&gt;
expansion, column sort (name / size / mtime), preview, and&lt;br /&gt;
double-click-to-open-in-editor all behave normally.  The first&lt;br /&gt;
click on a host takes ~200–500 ms (TCP + KEX + auth); subsequent&lt;br /&gt;
clicks reuse the pooled connection.&lt;br /&gt;
&lt;br /&gt;
URL syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sftp://[user@]host[:port]/remote/path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
User defaults to the local login name, port to 22, path to&lt;br /&gt;
&amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Tools menu offers four browser actions, three of them gated on&lt;br /&gt;
the SSH library being loaded:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; — opens the same key-generation&lt;br /&gt;
  dialog described under [[#Generating an SSH key pair]] below.&lt;br /&gt;
* &#039;&#039;&#039;SSH Connect...&#039;&#039;&#039; — opens an interactive VT100 terminal to a&lt;br /&gt;
  remote host.&lt;br /&gt;
* &#039;&#039;&#039;SFTP Connect...&#039;&#039;&#039; — points this browser tab at a remote&lt;br /&gt;
  filesystem via SFTP.&lt;br /&gt;
* &#039;&#039;&#039;Filesystem Info...&#039;&#039;&#039; — shows size, free space and usage of&lt;br /&gt;
  the filesystem holding the currently displayed directory.  Works&lt;br /&gt;
  uniformly for local paths and SFTP paths; for SFTP it requires&lt;br /&gt;
  the server to advertise the &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt;&lt;br /&gt;
  extension (every modern OpenSSH does).  Sizes are reported in&lt;br /&gt;
  IEC binary units (MiB, GiB, TiB) — the largest unit yielding a&lt;br /&gt;
  value ≥ 1 is chosen, so a TB-scale volume reads as &#039;&#039;X TiB&#039;&#039;&lt;br /&gt;
  rather than &#039;&#039;10240 GiB&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== From expecco actions ==&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin&lt;br /&gt;
([[Expecco::RemoteAccessImportPlugin]]) exposes the following test&lt;br /&gt;
actions to the expecco action palette:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection&#039;&#039;&#039; — opens an SSH session&lt;br /&gt;
  via the platform&#039;s &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; binary (PuTTY&#039;s&lt;br /&gt;
  &amp;lt;code&amp;gt;plink&amp;lt;/code&amp;gt; on Windows).&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open SSH Remote Connection and PublicKey&#039;&#039;&#039; — same&lt;br /&gt;
  but with explicit public-key authentication.&lt;br /&gt;
&lt;br /&gt;
To run these you need a configured keypair (private key on this&lt;br /&gt;
machine, public key in the remote host&#039;s&lt;br /&gt;
&amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;).  Generate one via the dialog&lt;br /&gt;
below or via &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The plugin also adds a settings page at &#039;&#039;&#039;Extras → Settings →&lt;br /&gt;
Plugins → Remote Access — SSH Keys&#039;&#039;&#039; carrying a single&lt;br /&gt;
&#039;&#039;&#039;Generate SSH Key Pair...&#039;&#039;&#039; button that opens the same dialog.&lt;br /&gt;
&lt;br /&gt;
== Generating an SSH key pair ==&lt;br /&gt;
&lt;br /&gt;
=== The dialog (FileBrowserV2 / settings page) ===&lt;br /&gt;
&lt;br /&gt;
The dialog asks for all parameters in one form:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Comment&#039;&#039;&#039; — embedded in the generated key (defaults to&lt;br /&gt;
  &amp;lt;code&amp;gt;stx@&amp;amp;lt;hostname&amp;amp;gt;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &#039;&#039;&#039;Storage&#039;&#039;&#039;:&lt;br /&gt;
** &#039;&#039;Save to disk file only&#039;&#039; — writes &amp;lt;code&amp;gt;~/.ssh/id_ed25519_stx&amp;lt;/code&amp;gt;&lt;br /&gt;
   (or wherever) plus a matching &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; companion.&lt;br /&gt;
** &#039;&#039;Save to disk AND load into ssh-agent&#039;&#039; — writes the file and&lt;br /&gt;
   also hands the key to the running ssh-agent.&lt;br /&gt;
** &#039;&#039;Load into ssh-agent only&#039;&#039; — key lives in agent memory only;&lt;br /&gt;
   gone on agent restart.&lt;br /&gt;
* &#039;&#039;&#039;Private key file&#039;&#039;&#039; — full path; disabled in agent-only mode.&lt;br /&gt;
* &#039;&#039;&#039;Passphrase / Confirm&#039;&#039;&#039; — empty leaves the on-disk file&lt;br /&gt;
  unencrypted (agent-only mode ignores the passphrase, since the&lt;br /&gt;
  OpenSSH agent wire protocol carries only the decrypted key).&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;Generate&#039;&#039;&#039;, the public-key line (the same&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-ed25519 AAAA... comment&amp;lt;/code&amp;gt; string ssh-keygen&lt;br /&gt;
emits) is copied to the system clipboard for pasting into the&lt;br /&gt;
remote host&#039;s &amp;lt;code&amp;gt;~/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== From a workspace ===&lt;br /&gt;
&lt;br /&gt;
For headless deployments, sandboxed builds, or scripts,&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; exposes a pure-Smalltalk key generator&lt;br /&gt;
that produces output bit-compatible with&lt;br /&gt;
&amp;lt;code&amp;gt;ssh-keygen -t ed25519&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| seed comment priv |&lt;br /&gt;
seed    := SSH::Client generateEd25519Seed.&lt;br /&gt;
comment := &#039;stx@&#039;, OperatingSystem getHostName.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Save passphrase-encrypted to disk&amp;quot;&lt;br /&gt;
priv := (Filename homeDirectory / &#039;.ssh&#039; / &#039;id_ed25519_stx&#039;) pathName.&lt;br /&gt;
SSH::Client&lt;br /&gt;
    saveOpenSshEd25519Seed:seed&lt;br /&gt;
    toFile:priv&lt;br /&gt;
    comment:comment&lt;br /&gt;
    passphrase:&#039;choose-something-long&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ AND load into the running agent&amp;quot;&lt;br /&gt;
SSH::Client addEd25519SeedToAgent:seed comment:comment.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/ Print the public-key line to paste into authorized_keys&amp;quot;&lt;br /&gt;
Transcript showCR:&lt;br /&gt;
    (SSH::Client authorizedKeysLineForEd25519Seed:seed comment:comment).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keys generated this way are interoperable with OpenSSH&#039;s own&lt;br /&gt;
tooling (&amp;lt;code&amp;gt;ssh-keygen -y -f ...&amp;lt;/code&amp;gt; re-derives the public&lt;br /&gt;
key, &amp;lt;code&amp;gt;ssh-keygen -p -f ...&amp;lt;/code&amp;gt; changes the passphrase,&lt;br /&gt;
etc.).&lt;br /&gt;
&lt;br /&gt;
=== Using the shell tools instead ===&lt;br /&gt;
&lt;br /&gt;
The traditional path also works:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -C &amp;quot;stx@your.host&amp;quot;&lt;br /&gt;
ssh-copy-id user@remotehost&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preparing ssh-agent ==&lt;br /&gt;
&lt;br /&gt;
The agent path is strongly preferred over reading raw keyfiles: it&lt;br /&gt;
keeps encrypted private keys unlocked once per session, and handles&lt;br /&gt;
identities (hardware-token-backed keys, KeePassXC entries) that&lt;br /&gt;
ST/X should never see directly.&lt;br /&gt;
&lt;br /&gt;
ST/X picks the agent path automatically when&lt;br /&gt;
&amp;lt;code&amp;gt;$SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is set in the process environment&lt;br /&gt;
&#039;&#039;&#039;at the time stx is launched&#039;&#039;&#039;.  Setting it later from a&lt;br /&gt;
workspace does not help.&lt;br /&gt;
&lt;br /&gt;
=== Linux / macOS ===&lt;br /&gt;
&lt;br /&gt;
Most desktop distributions launch an agent automatically as part of&lt;br /&gt;
the session (gnome-keyring on GNOME, ssh-agent.service on systemd,&lt;br /&gt;
KWallet on KDE).  Verify in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo $SSH_AUTH_SOCK    # /run/user/1000/keyring/ssh or similar&lt;br /&gt;
ssh-add -l             # lists loaded identities&lt;br /&gt;
ssh-add ~/.ssh/id_ed25519   # load yours if not loaded&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If no agent runs at all, add this snippet to your shell rc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ~/.bashrc or ~/.zshrc&lt;br /&gt;
if [ -z &amp;quot;$SSH_AUTH_SOCK&amp;quot; ]; then&lt;br /&gt;
    eval &amp;quot;$(ssh-agent -s)&amp;quot; &amp;gt; /dev/null&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ST/X must be launched from a shell that has seen this rc — a&lt;br /&gt;
desktop launcher started from the file manager does NOT inherit&lt;br /&gt;
the variable.  Wrap the stx start command in a small script under&lt;br /&gt;
&amp;lt;code&amp;gt;~/.local/bin/&amp;lt;/code&amp;gt; that sources the rc first.&lt;br /&gt;
&lt;br /&gt;
The Remote Access settings page (&#039;&#039;&#039;Extras → Settings → Plugins&lt;br /&gt;
→ Remote Access — SSH Keys&#039;&#039;&#039;) shows whether the running image&lt;br /&gt;
sees an agent.&lt;br /&gt;
&lt;br /&gt;
==== Permanent setup via systemd ====&lt;br /&gt;
&lt;br /&gt;
For a truly cross-session agent (survives desktop logouts, comes&lt;br /&gt;
up automatically at next login), enable the per-user systemd&lt;br /&gt;
unit shipped with most distros&#039; &amp;lt;code&amp;gt;openssh-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl --user enable --now ssh-agent.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then point &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the user-service socket&lt;br /&gt;
in your shell rc (this replaces the &amp;lt;code&amp;gt;eval $(ssh-agent -s)&amp;lt;/code&amp;gt;&lt;br /&gt;
snippet above):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export SSH_AUTH_SOCK=&amp;quot;${XDG_RUNTIME_DIR}/ssh-agent.socket&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
To skip the manual &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; step, let OpenSSH load&lt;br /&gt;
keys into the agent automatically the first time they are needed.&lt;br /&gt;
Add to &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first SSH connection then prompts for the key passphrase&lt;br /&gt;
once and hands the unlocked key to the agent; subsequent&lt;br /&gt;
connections use the cached identity without prompting.&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Windows 10+ ships native OpenSSH including an agent service.&lt;br /&gt;
One-time setup:&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Services&#039;&#039;&#039; (&amp;lt;code&amp;gt;services.msc&amp;lt;/code&amp;gt;) as Administrator.&lt;br /&gt;
# Find &#039;&#039;&#039;OpenSSH Authentication Agent&#039;&#039;&#039;, set Startup Type to&lt;br /&gt;
  &#039;&#039;&#039;Automatic&#039;&#039;&#039;, click &#039;&#039;&#039;Start&#039;&#039;&#039;.&lt;br /&gt;
# In PowerShell: &amp;lt;code&amp;gt;ssh-add $HOME\.ssh\id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Verify: &amp;lt;code&amp;gt;ssh-add -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The Windows OpenSSH agent listens on a named pipe&lt;br /&gt;
(&amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;), not a Unix socket.  ST/X&lt;br /&gt;
supports both transports, but Windows ssh-add does &#039;&#039;&#039;not&#039;&#039;&#039; set&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; for you.  Add it manually:&lt;br /&gt;
&lt;br /&gt;
# Press {{Key|Win}} → type &amp;quot;environment&amp;quot; → &amp;quot;Edit the system environment variables&amp;quot;.&lt;br /&gt;
# &#039;&#039;&#039;Environment Variables&#039;&#039;&#039; → under &#039;&#039;&#039;User variables&#039;&#039;&#039;, &#039;&#039;&#039;New&#039;&#039;&#039;.&lt;br /&gt;
# Name: &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt;&lt;br /&gt;
# Value: &amp;lt;code&amp;gt;\\.\pipe\openssh-ssh-agent&amp;lt;/code&amp;gt;&lt;br /&gt;
# Log out and back in (or restart stx) so the new env propagates.&lt;br /&gt;
&lt;br /&gt;
==== PowerShell quick-setup ====&lt;br /&gt;
&lt;br /&gt;
The same setup from an &#039;&#039;&#039;elevated&#039;&#039;&#039; PowerShell prompt, for&lt;br /&gt;
scripts or unattended provisioning:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Start the agent now AND on every reboot (permanent).&lt;br /&gt;
Set-Service -Name ssh-agent -StartupType Automatic&lt;br /&gt;
Start-Service ssh-agent&lt;br /&gt;
&lt;br /&gt;
# Persist SSH_AUTH_SOCK for the user (survives reboots).&lt;br /&gt;
[Environment]::SetEnvironmentVariable(&lt;br /&gt;
    &#039;SSH_AUTH_SOCK&#039;,&lt;br /&gt;
    &#039;\\.\pipe\openssh-ssh-agent&#039;,&lt;br /&gt;
    &#039;User&#039;)&lt;br /&gt;
&lt;br /&gt;
# Load a key (prompts for the passphrase if the file is encrypted).&lt;br /&gt;
ssh-add $HOME\.ssh\id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a one-shot agent start without making it persistent (e.g.&lt;br /&gt;
single-session test), drop the &amp;lt;code&amp;gt;Set-Service&amp;lt;/code&amp;gt; line and&lt;br /&gt;
just run &amp;lt;code&amp;gt;Start-Service ssh-agent&amp;lt;/code&amp;gt;.  The env-var line&lt;br /&gt;
can also be omitted if &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; is only needed&lt;br /&gt;
in the current shell — use &amp;lt;code&amp;gt;$env:SSH_AUTH_SOCK = &#039;...&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
instead for that session-local form.&lt;br /&gt;
&lt;br /&gt;
On stripped-down Windows installs the ssh-agent service may not&lt;br /&gt;
be present.  Add it once via &#039;&#039;&#039;Settings → Apps → Optional&lt;br /&gt;
features → OpenSSH Client&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Alternative agents:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PuTTY pageant&#039;&#039;&#039; — uses its own protocol; NOT supported by&lt;br /&gt;
  ST/X&#039;s SSH::Agent.  Migrate the keys to OpenSSH.&lt;br /&gt;
* &#039;&#039;&#039;Git for Windows ssh-agent&#039;&#039;&#039; — works; point&lt;br /&gt;
  &amp;lt;code&amp;gt;SSH_AUTH_SOCK&amp;lt;/code&amp;gt; at the socket it publishes.&lt;br /&gt;
* &#039;&#039;&#039;WSL 2&#039;&#039;&#039; — a ST/X inside WSL sees WSL&#039;s Linux agent normally;&lt;br /&gt;
  a ST/X on the Windows side does not.  Bridging needs a helper&lt;br /&gt;
  like &amp;lt;code&amp;gt;npiperelay&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Verify in the Remote Access settings page&lt;br /&gt;
(&#039;&#039;&#039;Extras → Settings → Plugins → Remote Access — SSH Keys&#039;&#039;&#039;) —&lt;br /&gt;
the agent indicator there reports whether the running image sees&lt;br /&gt;
the agent.&lt;br /&gt;
&lt;br /&gt;
==== Auto-loading keys on first use ====&lt;br /&gt;
&lt;br /&gt;
Windows OpenSSH does &#039;&#039;&#039;not&#039;&#039;&#039; persist agent-loaded keys across&lt;br /&gt;
agent restarts.  To avoid running &amp;lt;code&amp;gt;ssh-add&amp;lt;/code&amp;gt; manually&lt;br /&gt;
after each reboot, add the same lazy-load configuration to&lt;br /&gt;
&amp;lt;code&amp;gt;%USERPROFILE%\.ssh\config&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host *&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenSSH then loads the key into the agent on first use (prompts&lt;br /&gt;
for the passphrase once) and reuses it for the rest of the&lt;br /&gt;
session.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
All tunables are class-side on &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Accessor !! Default !! What it controls&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#idleEvictionSeconds:&amp;lt;/code&amp;gt; || 240 (4 min) || How long a pooled&lt;br /&gt;
connection sits idle before the next access proactively closes +&lt;br /&gt;
reopens it.  Just under typical sshd&lt;br /&gt;
&amp;lt;code&amp;gt;ClientAliveInterval × ClientAliveCountMax&amp;lt;/code&amp;gt; so we recycle&lt;br /&gt;
before the server TCP-RESETs us.  Pass &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; to restore&lt;br /&gt;
the default.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#attrsCacheTtlSeconds:&amp;lt;/code&amp;gt; || 5 || Max age (s) of a&lt;br /&gt;
cached STAT before &amp;lt;code&amp;gt;#ensureAttrs&amp;lt;/code&amp;gt; refetches.  Parent&lt;br /&gt;
listDir always re-stamps fresh attrs onto children, so navigating&lt;br /&gt;
an open directory does not pay the TTL.  Set to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to&lt;br /&gt;
disable caching.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#closeAllConnections&amp;lt;/code&amp;gt; || (action) || Tears down every&lt;br /&gt;
pooled connection.  Useful after a known-bad network event, before&lt;br /&gt;
a deliberate identity swap, or as part of a clean image shutdown.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Diagnostics ==&lt;br /&gt;
&lt;br /&gt;
=== SemaphoreMonitor ===&lt;br /&gt;
&lt;br /&gt;
Open &amp;lt;code&amp;gt;SemaphoreMonitor&amp;lt;/code&amp;gt; from the Launcher&#039;s &amp;quot;Status&amp;quot;&lt;br /&gt;
sub-menu.  Per-host SFTP mutex appears as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt;; the pool-wide mutex as&lt;br /&gt;
&amp;lt;code&amp;gt;SFTP/pool&amp;lt;/code&amp;gt;.  Right-click a row:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Copy Waiters Stack to Clipboard&#039;&#039;&#039; — dumps the last-owner&#039;s&lt;br /&gt;
  walkback plus each waiter&#039;s, formatted as plain text.  Use when&lt;br /&gt;
  a process is wedged in &amp;lt;code&amp;gt;readWait&amp;lt;/code&amp;gt; inside&lt;br /&gt;
  &amp;lt;code&amp;gt;withSftpClientDo:&amp;lt;/code&amp;gt; and you need to see which SFTP&lt;br /&gt;
  request it is on.&lt;br /&gt;
* &#039;&#039;&#039;Copy List to Clipboard&#039;&#039;&#039; — the whole table, for an&lt;br /&gt;
  email-this-to-someone diagnosis.&lt;br /&gt;
* &#039;&#039;&#039;Detect Deadlocks&#039;&#039;&#039; — DFS over the wait-for graph, reports&lt;br /&gt;
  cycles.&lt;br /&gt;
&lt;br /&gt;
=== Logger ===&lt;br /&gt;
&lt;br /&gt;
The SSH stack logs interesting events:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; on auto-reconnect after a dead connection.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when a pool entry is idle-evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning:&amp;lt;/code&amp;gt; when an SSH key file cannot be parsed&lt;br /&gt;
  (e.g. legacy PEM, encrypted-without-agent) — the file is skipped,&lt;br /&gt;
  others tried.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;SFTP v3 only.&#039;&#039;&#039;  No SETSTAT (no remote chmod / chown / utime),&lt;br /&gt;
  no SSH_FXP_READLINK exposed (&amp;lt;code&amp;gt;#isSymbolicLink&amp;lt;/code&amp;gt; always&lt;br /&gt;
  &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#linkInfo&amp;lt;/code&amp;gt; returns the regular&lt;br /&gt;
  stat info).  Several SFTPv5+ niceties are nevertheless picked up&lt;br /&gt;
  via OpenSSH SSH_FXP_EXTENDED requests — see&lt;br /&gt;
  [[#OpenSSH SFTP extensions]] below.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation.&#039;&#039;&#039;  Two concurrent operations on the&lt;br /&gt;
  same host queue through the host mutex.  See [[#Future work]].&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#renameTo:&amp;lt;/code&amp;gt; fallback has a TOCTOU window.&#039;&#039;&#039;  On&lt;br /&gt;
  servers that advertise &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; (every&lt;br /&gt;
  modern OpenSSH does), overwrite is atomic; on the rare server&lt;br /&gt;
  that does not, the receiver is emulated as delete-then-rename&lt;br /&gt;
  and another process can race in between.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt; is heuristic.&#039;&#039;&#039;  Always&lt;br /&gt;
  returns &amp;lt;code&amp;gt;#isDirectory&amp;lt;/code&amp;gt; (the accurate answer would cost&lt;br /&gt;
  three round-trips per directory icon, which made the original tree&lt;br /&gt;
  expansion unbearably slow).&lt;br /&gt;
&lt;br /&gt;
== Implementation details ==&lt;br /&gt;
&lt;br /&gt;
For readers wanting the architecture.  Five classes, top-down:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Class !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpFilename&amp;lt;/code&amp;gt; || Filename subclass; the public&lt;br /&gt;
API.  Maps &amp;lt;code&amp;gt;sftp://...&amp;lt;/code&amp;gt; URLs to remote files; exposes&lt;br /&gt;
&amp;lt;code&amp;gt;directoryContents&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;readingFileDo:&amp;lt;/code&amp;gt;,&lt;br /&gt;
&amp;lt;code&amp;gt;renameTo:&amp;lt;/code&amp;gt; etc.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt; || SFTP-v3 protocol&lt;br /&gt;
(request/response codec, listDir, stat, open, read, write, mkdir).&lt;br /&gt;
Driven by SftpFilename.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Channel&amp;lt;/code&amp;gt; || SSH channel multiplexer&lt;br /&gt;
(CHANNEL_OPEN, DATA, EOF, CLOSE, WINDOW_ADJUST).  One logical&lt;br /&gt;
session per Channel instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; || High-level SSH client: opens the&lt;br /&gt;
transport, runs KEX, host-key check, userauth, then dispenses&lt;br /&gt;
Channels.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SSH::Transport&amp;lt;/code&amp;gt; || Wire layer.  Banner + KEXINIT&lt;br /&gt;
exchange, ChaCha20-Poly1305 packet framing, sendSeq / recvSeq,&lt;br /&gt;
heartbeat, SSH_MSG_DISCONNECT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OpenSSH SFTP extensions ===&lt;br /&gt;
&lt;br /&gt;
SFTP v3 (RFC draft-ietf-secsh-filexfer-02) is intentionally minimal.&lt;br /&gt;
OpenSSH ships an open-ended extension mechanism: the server lists&lt;br /&gt;
extension names it understands in its &amp;lt;code&amp;gt;SSH_FXP_VERSION&amp;lt;/code&amp;gt;&lt;br /&gt;
reply, and the client invokes them via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH_FXP_EXTENDED(200)&amp;lt;/code&amp;gt; packets carrying the extension&lt;br /&gt;
name as the first string.  Each extension is feature-detected via&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::SftpClient&amp;amp;gt;&amp;amp;gt;supportsExtension:&amp;lt;/code&amp;gt;; callers fall&lt;br /&gt;
back when the server doesn&#039;t advertise it.&lt;br /&gt;
&lt;br /&gt;
The stack uses four of the OpenSSH extensions today:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; — atomic&lt;br /&gt;
  rename-with-overwrite.  Picked up automatically by&lt;br /&gt;
  &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;renameTo:&amp;lt;/code&amp;gt;; the delete-then-rename&lt;br /&gt;
  fallback only fires on servers that lack it.&lt;br /&gt;
* &amp;lt;code&amp;gt;hardlink@openssh.com&amp;lt;/code&amp;gt; — create a POSIX hard link.&lt;br /&gt;
  Exposed as &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;createHardLinkAs:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;statvfs@openssh.com&amp;lt;/code&amp;gt; — POSIX&lt;br /&gt;
  &amp;lt;code&amp;gt;statvfs(3)&amp;lt;/code&amp;gt;-shape filesystem stats.  Exposed as&lt;br /&gt;
  &amp;lt;code&amp;gt;SftpFilename&amp;amp;gt;&amp;amp;gt;fileSystemInfo&amp;lt;/code&amp;gt;; the result is&lt;br /&gt;
  shape-compatible with &amp;lt;code&amp;gt;OperatingSystem getDiskInfoOf:&amp;lt;/code&amp;gt;&lt;br /&gt;
  so callers can treat local and remote uniformly.  Drives the&lt;br /&gt;
  &#039;&#039;&#039;Tools &amp;amp;rarr; Filesystem Info...&#039;&#039;&#039; menu entry described at the&lt;br /&gt;
  top of this page.&lt;br /&gt;
* &amp;lt;code&amp;gt;fsync@openssh.com&amp;lt;/code&amp;gt; — flush server-side write buffer&lt;br /&gt;
  to disk on an open handle.  Available on the low-level&lt;br /&gt;
  &amp;lt;code&amp;gt;SftpClient&amp;amp;gt;&amp;amp;gt;fsyncHandle:&amp;lt;/code&amp;gt;; not yet plumbed&lt;br /&gt;
  into a Filename-level &amp;quot;durable write&amp;quot; API.&lt;br /&gt;
&lt;br /&gt;
The remaining OpenSSH extensions&lt;br /&gt;
(&amp;lt;code&amp;gt;lsetstat@openssh.com&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fstatvfs@openssh.com&amp;lt;/code&amp;gt;)&lt;br /&gt;
are recognised in the advertised-extensions list but not wrapped at&lt;br /&gt;
Filename level — there&#039;s no Filename-side caller for them yet.&lt;br /&gt;
&lt;br /&gt;
=== Connection pooling ===&lt;br /&gt;
&lt;br /&gt;
Every &amp;lt;code&amp;gt;SftpFilename&amp;lt;/code&amp;gt; instance pointing at the same&lt;br /&gt;
&amp;lt;code&amp;gt;user@host:port&amp;lt;/code&amp;gt; triple shares one&lt;br /&gt;
&amp;lt;code&amp;gt;SSH::Client&amp;lt;/code&amp;gt; plus one &amp;lt;code&amp;gt;SSH::SftpClient&amp;lt;/code&amp;gt;.&lt;br /&gt;
Pool is class-side, guarded by a single&lt;br /&gt;
&amp;lt;code&amp;gt;ConnectionPoolMutex&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Lazy bring-up&#039;&#039;&#039; — TCP + KEX + userauth + SFTP INIT happens&lt;br /&gt;
  on the first SFTP operation, not on &amp;lt;code&amp;gt;forUrl:&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Per-host serialisation&#039;&#039;&#039; — SFTP requests on a given host&lt;br /&gt;
  are serialised through a &amp;lt;code&amp;gt;RecursionLock&amp;lt;/code&amp;gt; named&lt;br /&gt;
  &amp;lt;code&amp;gt;SFTP/&amp;amp;lt;user@host:port&amp;amp;gt;&amp;lt;/code&amp;gt; (visible in&lt;br /&gt;
  SemaphoreMonitor).&lt;br /&gt;
* &#039;&#039;&#039;Idle eviction&#039;&#039;&#039; — unused for longer than&lt;br /&gt;
  &amp;lt;code&amp;gt;idleEvictionSeconds&amp;lt;/code&amp;gt;, the entry is proactively&lt;br /&gt;
  closed + reopened on the next access.&lt;br /&gt;
* &#039;&#039;&#039;Auto-reconnect&#039;&#039;&#039; — a transport-level failure (broken pipe,&lt;br /&gt;
  EOF, MNU on nil socket) evicts the dead pool entry, opens a&lt;br /&gt;
  fresh client, retries the request &#039;&#039;&#039;once&#039;&#039;&#039;.  Application-level&lt;br /&gt;
  SFTP STATUS errors propagate immediately.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
Tracked but not yet implemented:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Multi-channel parallelism per host&#039;&#039;&#039; — today one TCP +&lt;br /&gt;
  one SFTP channel per host means N concurrent requests&lt;br /&gt;
  serialise.  Pipelining over multiple SshClients in the pool&lt;br /&gt;
  (preferred), or a transport-level reader process demultiplexing&lt;br /&gt;
  to per-channel inboxes, would let the tree pane keep listing&lt;br /&gt;
  while the content pane reads a large file.&lt;br /&gt;
* &#039;&#039;&#039;Accurate &amp;lt;code&amp;gt;#isNonEmptyDirectory&amp;lt;/code&amp;gt;&#039;&#039;&#039; via OPEN_DIR&lt;br /&gt;
  + READ_DIR (first batch only) + CLOSE — three RTTs per probe;&lt;br /&gt;
  needs SftpClient to pipeline requests before this pays off.&lt;br /&gt;
* &#039;&#039;&#039;SFTP v5/v6 negotiation&#039;&#039;&#039; for extended attrs and FTP-style&lt;br /&gt;
  canonicalisation.  (Atomic-overwrite rename is already handled&lt;br /&gt;
  via the OpenSSH &amp;lt;code&amp;gt;posix-rename@openssh.com&amp;lt;/code&amp;gt; extension;&lt;br /&gt;
  see [[#OpenSSH SFTP extensions]].)&lt;br /&gt;
&lt;br /&gt;
= Command Shell =&lt;br /&gt;
&lt;br /&gt;
Local command shell on this expecco machine.  Typical applications:&lt;br /&gt;
local command-line, running a local helper tool, bridging a&lt;br /&gt;
remote workflow to a local utility.&lt;br /&gt;
&lt;br /&gt;
The Expecco RemoteAccess plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Open&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;CmdShell - Close&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No credentials, no network — runs as the expecco process&#039;s own&lt;br /&gt;
user.  Output streams to expecco&#039;s log.&lt;br /&gt;
&lt;br /&gt;
= Telnet =&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.svg|24px|Warning]] &#039;&#039;&#039;Telnet is a legacy protocol&lt;br /&gt;
with no encryption.&#039;&#039;&#039; Passwords are transmitted in plain text on&lt;br /&gt;
the wire; anyone on the network path can read them.  Use Telnet&lt;br /&gt;
ONLY when the target device has no other option (typically: old&lt;br /&gt;
industrial controllers, lab instruments, embedded measurement&lt;br /&gt;
equipment without an SSH stack).  For everything else use&lt;br /&gt;
[[#SSH and SFTP]].&lt;br /&gt;
&lt;br /&gt;
The expecco plugin exposes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Open Remote Connection With Login&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Telnet - Execute Remote Command&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Example - Remote Device Control via Telnet&#039;&#039;&#039; (internal demo)&lt;br /&gt;
&lt;br /&gt;
The Telnet protocol (RFC 854) is a bidirectional 8-bit byte stream&lt;br /&gt;
over TCP, with in-band control sequences for terminal options.&lt;br /&gt;
A connection is established to a target host:port; after optional&lt;br /&gt;
in-band login, both sides can send data.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
&lt;br /&gt;
* [[SSH Client/en|SSH::Client]] — the SSH layer (exec, TTY, agent&lt;br /&gt;
  forwarding, ProxyJump).&lt;br /&gt;
* [[FileBrowserV2/en|FileBrowserV2]] — the main UI client of&lt;br /&gt;
  this stack.&lt;br /&gt;
* [[ClaudeCode plugin/en|Claude Code]] — uses the same SSH stack&lt;br /&gt;
  for its HTTPS transport.&lt;br /&gt;
* [[Wikipedia:Secure Shell|RFC 4251 (SSH-2 Architecture)]]&lt;br /&gt;
* [[Wikipedia:Telnet|RFC 854 (Telnet Protocol)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Network]]&lt;br /&gt;
[[Category:SSH]]&lt;/div&gt;</summary>
		<author><name>Sv</name></author>
	</entry>
</feed>