{"_id":"@astrakratos/tetherd","_rev":"10-61357e8d0b161ea313187fb6f3f8676e","name":"@astrakratos/tetherd","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.0":{"name":"@astrakratos/tetherd","version":"0.2.0","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.0","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AkhilAbhilashKella1711/tether#readme","bugs":{"url":"https://github.com/AkhilAbhilashKella1711/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"e80ef467c90a0df5732121e99af1986b8202b879","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.0.tgz","fileCount":23,"integrity":"sha512-EEip6ZPwtYn1rX+GZMTUzbPeXZY8QddADUWEWiC4qdlDZ7WI4q6n56NCHpC48WgXgW3tQKAp7KgrqqSaHnZLxw==","signatures":[{"sig":"MEYCIQC/g31lP6maqclYGTIVrF2TMK/vntc02c5avLiOq7xw5wIhAIZEvdcVDIbz1kClOMNENddpG6iUOjp5+E1yE5LkEqOX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":352404},"type":"module","engines":{"node":">=22.5.0"},"scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AkhilAbhilashKella1711/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.0_1788427496520_0.4928149714794845","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@astrakratos/tetherd","version":"0.2.1","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.1","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"29cb7c87dfa74cdbeffbb1e53f26fac33bc487b6","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.1.tgz","fileCount":24,"integrity":"sha512-H33z4pf0ZRqld7Zk7WcfgWSHs9v6KM9KtMCEQxxfq+0fKFH1i+3JzUDn66P0uhcCzn6HfH32jbRtLz804VWsfw==","signatures":[{"sig":"MEQCIFL7DF816ilzYqOj+5hFOK2+fxFozEyl1wf/1A6cGlNTAiBwAqMORRN107/8/Gf7tQ8fWToWsYfaGdJwTNvXvZBd3w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":388858},"type":"module","engines":{"node":">=22.5.0"},"gitHead":"1527f088794e647cc31f554377cd22604e5c6551","scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AstraKratos/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.1_1788444781819_0.813299536242563","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@astrakratos/tetherd","version":"0.2.2","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.2","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"7d9ae996c69e327ad2076c2f813618bb3085ec50","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.2.tgz","fileCount":24,"integrity":"sha512-+vr4lxVrunglCy7LtK6OrRe5Mi3BWihS2lz3G4To2DZNHFnF/r6IJb8BQyPVlxlu+SoUSmu1EzELjkcuEzV9nw==","signatures":[{"sig":"MEUCICODqO1Ah7fWESYgt4v38S0M/rqr10hOfsbO9tKS8zTAAiEApyf152KSDvH3P5CxSGg0L8C9nmT5NFLqzsALM4B/Muk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":395450},"type":"module","engines":{"node":">=22.5.0"},"gitHead":"b8ead66d14024491a79867ad4d77a4c982a37da3","scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AstraKratos/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.2_1788445761797_0.2960529452554064","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@astrakratos/tetherd","version":"0.2.3","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.3","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"865a28fe5d2cd5a3e4cabf52dea4174d4d1d3f2b","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.3.tgz","fileCount":24,"integrity":"sha512-uvs8C4SfSUF4zxiECLfKq4kn/5BrmFoGQasRPGQKc9meYV/ED0n4wiSfOl2QbGdbDM/U2qY8shgOJChq2+YEBw==","signatures":[{"sig":"MEYCIQC4FrZxAYuT/Xpv2I+hculfSUgbBM4tguGChZEkcY6PGAIhAOTk5QV5C+YUvVGHv5Wpw/ofVNkV4Dp6WD7Q0cXJNzfU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":402119},"type":"module","engines":{"node":">=22.5.0"},"gitHead":"64208c6b4dae6017798493e1bd3593e2171c53c8","scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AstraKratos/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.3_1788450158713_0.07546861964894669","host":"s3://npm-registry-packages-npm-production"}},"0.2.4":{"name":"@astrakratos/tetherd","version":"0.2.4","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.4","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"36e9867bfcae88b0e3680a7d5aa2cf423ad28153","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.4.tgz","fileCount":24,"integrity":"sha512-AjS1GRJiAZ4hcuKNY0oEkvJiowhNPVGZTA02Fp0k7CdIHfZ7v+eBmJ2wSmGG+FbtsIiu/1q6NhRwJ9Ddax3ZrA==","signatures":[{"sig":"MEUCIQCAhw0Y0bGrIaY3NDOk9PbD2ee5DonxnZixefY0MXxslwIgSIG5BRH+QvBVYMjxp6udmveYpE9WExcGHnWS1L/l7sI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":408960},"type":"module","engines":{"node":">=22.5.0"},"gitHead":"3117834132d8255fffd11eea31efdeb0edebcd4e","scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AstraKratos/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.4_1788502872601_0.5105562777068806","host":"s3://npm-registry-packages-npm-production"}},"0.2.5":{"name":"@astrakratos/tetherd","version":"0.2.5","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.5","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"c2fdadf9c97eaa510c597dcd150010c61a37dbb1","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.5.tgz","fileCount":25,"integrity":"sha512-3LzBnjNhRqwTFNV3Dsv6ccONmiKQXGMuOqhtH1QnQD5waMjviHMYxIDRNbhmQfl3sfKktWzpBa7VYCzYkhmFsw==","signatures":[{"sig":"MEUCIQCppYOorA1WS0GGtGECMPQZ16L7KtfxZApUb/m94/J8LgIgchRRJwobG93UWJGqDUj65ZCCmzodkfV+zsA14HqDIDo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":457531},"type":"module","engines":{"node":">=22.5.0"},"gitHead":"6dcd6c1fbe75f5fa74e527b3656e39b22bc4c7a8","scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AstraKratos/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.5_1788503392362_0.9743918532335789","host":"s3://npm-registry-packages-npm-production"}},"0.2.6":{"name":"@astrakratos/tetherd","version":"0.2.6","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.6","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"33836c94d1a78093390131c8066895c086058bab","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.6.tgz","fileCount":25,"integrity":"sha512-lDu2qcoL47CqbKk3GPBKExeWLTBqPmmfeZ40pmpfN04P4D8pceFte/BpkXgFgsN3lyE/I0+3Ze91h2yHPyZV6A==","signatures":[{"sig":"MEUCICAxxgYOTOjoE01Iq4JAuqY/b2cDXnnl6Bej+u3zny7bAiEA6/Cnagdh1xJPRv09NNMkym+rPaxT8OmF0hdSevgnwkg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":458324},"type":"module","engines":{"node":">=22.5.0"},"gitHead":"b24755fad745060cac923b42988dfce6cf8d4a09","scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AstraKratos/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.6_1788531013246_0.08552358600547216","host":"s3://npm-registry-packages-npm-production"}},"0.2.7":{"name":"@astrakratos/tetherd","version":"0.2.7","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.7","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"5b56eaa55182f509ac88e7f73d32c8d7729b3421","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.7.tgz","fileCount":25,"integrity":"sha512-VREt12FqkF8+eSj7J+CWlgadxFA5U1kNKGnRFTmawtkkUWrbv2pHJ3WmqeD/mqoh0yXWDZ0z5wKAEmfCcfi+RA==","signatures":[{"sig":"MEYCIQCyg4EyVea24Q9Ek1xPVLShuYf5vXQAt7DmnKdjMzbD1wIhANzp4pTYoljI0yucwBPeBl4DvYlBzS6obn8YHa4epK8q","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":458809},"type":"module","engines":{"node":">=22.5.0"},"gitHead":"9fba83093f4846de0fc13edc6ef1f6000db45648","scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AstraKratos/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.7_1788533961429_0.9304319864150505","host":"s3://npm-registry-packages-npm-production"}},"0.2.8":{"name":"@astrakratos/tetherd","version":"0.2.8","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","_id":"@astrakratos/tetherd@0.2.8","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"os":["darwin","linux","win32"],"bin":{"tetherd":"daemon/tetherd.mjs"},"dist":{"shasum":"e1aaab32cf9d6a5db84adaa56e1e7dc62de9c78c","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.2.8.tgz","fileCount":25,"integrity":"sha512-8CznN1UqxA0ja/YvgIQLf1ZGoQek1WYU+DUJFRbQNkuiZuN68y5GiCvuO5djju4eEkY8TvjM93NTz9E7qPT1iA==","signatures":[{"sig":"MEUCIQC5qc5z6FYO9T26/3EtM9Da+/duTNmmT8d1SAqoIx/DFQIgOedJLbPL72UgHdZzWp4hgyeZ+sgN+pDU3tECib+mwhI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":466091},"type":"module","engines":{"node":">=22.5.0"},"gitHead":"b7cfab5d3603899ab76a0dd4dd08fe629b0acec1","scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"repository":{"url":"git+https://github.com/AstraKratos/tether.git","type":"git"},"_npmVersion":"10.9.4","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"ws":"^8.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/tetherd_0.2.8_1788535189674_0.8469942834747941","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@astrakratos/tetherd","version":"0.3.0","type":"module","description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"license":"MIT","bin":{"tetherd":"daemon/tetherd.mjs"},"engines":{"node":">=22.5.0"},"os":["darwin","linux","win32"],"scripts":{"relay":"node relay/server.mjs","daemon":"node daemon/tetherd.mjs run"},"dependencies":{"ws":"^8.18.0"},"repository":{"type":"git","url":"git+https://github.com/AstraKratos/tether.git"},"publishConfig":{"access":"public"},"homepage":"https://github.com/AstraKratos/tether#readme","bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"_id":"@astrakratos/tetherd@0.3.0","gitHead":"912334493283bb2efe909cde5130e4a86d57f114","_nodeVersion":"22.21.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-CLBwQ8QZ1XqYT/1bk2Ee2zjb8iJqlIrqAunPOdM6tlf00pnXwCsoLqz9qqyMkk1uMZgKo1M38dmIBFeCi2P04w==","shasum":"7101c1ff98d518c4a6de3ee73eeb69b2c31ba7c8","tarball":"https://registry.npmjs.org/@astrakratos/tetherd/-/tetherd-0.3.0.tgz","fileCount":27,"unpackedSize":478515,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDkausjSDsrbuoy/pS6sOwbcYXOCKQ8m5ewgV0+JXJ3LQIhAMO4MO21Yua/414mG7G8J8FRpbSaby9z2UVzP0z+NJ9n"}]},"_npmUser":{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"},"directories":{},"maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tetherd_0.3.0_1788538509464_0.12076503823579099"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-03T09:24:55.100Z","modified":"2026-09-04T16:15:09.794Z","0.2.0":"2026-09-03T09:24:56.923Z","0.2.1":"2026-09-03T14:13:01.956Z","0.2.2":"2026-09-03T14:29:22.014Z","0.2.3":"2026-09-03T15:42:38.870Z","0.2.4":"2026-09-04T06:21:12.961Z","0.2.5":"2026-09-04T06:29:52.526Z","0.2.6":"2026-09-04T14:10:13.407Z","0.2.7":"2026-09-04T14:59:21.573Z","0.2.8":"2026-09-04T15:19:49.837Z","0.3.0":"2026-09-04T16:15:09.618Z"},"bugs":{"url":"https://github.com/AstraKratos/tether/issues"},"license":"MIT","homepage":"https://github.com/AstraKratos/tether#readme","keywords":["claude-code","cursor","codex","ai-agent","remote","mirror","hooks"],"repository":{"type":"git","url":"git+https://github.com/AstraKratos/tether.git"},"description":"Mirror your local AI coding sessions (Claude Code, Cursor, Codex) to a web UI — watch them, answer their prompts, and steer them from anywhere. End-to-end encrypted.","maintainers":[{"name":"akhil_a.k17","email":"akhilkella17@gmail.com"}],"readme":"# Tether 📡\n\nMirror your local AI coding sessions — **Claude Code**, **Cursor**, **Codex** — to a web app you\ncan open from your phone, get notified the moment one needs you, and answer its questions from\nanywhere.\n\nTether **never changes what an agent does.** Every agent's own permission logic runs exactly as\nif Tether were not installed, and Tether never invents a prompt the agent would not have raised.\nWhat it adds is a second place to answer: when an agent genuinely stops to ask you something — a\npermission, a question, a plan to approve — that prompt appears in the web UI *and* in your\nterminal at the same time, and whichever you answer first wins.\n\nTranscripts are **end-to-end encrypted**: the relay stores ciphertext and routing metadata only.\nThe account key lives in your browser and on paired machines; it travels only inside pairing\ncodes you copy yourself.\n\n## Layout\n\n- `daemon/` — `tetherd`, runs on each machine: tails each agent's transcripts, installs\n  and removes their hooks, mirrors the questions they ask, and relays your answers back.\n  Zero third-party dependencies.\n- `daemon/agents.mjs` — per-agent integration (Claude Code, Codex, Cursor): where each keeps\n  its hooks, the shape they take, and which transcripts are tailable.\n- `daemon/service.mjs` — keeping it running per OS: launchd (macOS), systemd user unit\n  (Linux), Task Scheduler (Windows).\n- `relay/` — WebSocket gateway + SQLite store + serves the app. Deliberately blind.\n- `app/` — the web client (vanilla ES modules, no build step).\n- `test/client.mjs` — headless client speaking the same protocol; used for e2e tests.\n\n## Quick start (single machine)\n\n```bash\nnpm install                      # one dependency: ws\nnode relay/server.mjs            # relay on http://127.0.0.1:8787\n# open http://127.0.0.1:8787 in a browser -> Create account -> \"Pair a machine\"\n# run the printed command on the machine:\nnode daemon/tetherd.mjs pair 'TETHER1.…' --relay http://127.0.0.1:8787 --name my-mac\nnode daemon/tetherd.mjs run      # or: node daemon/tetherd.mjs launchd install\n```\n\nThe relay serves the landing page at `/` — what Tether is, how it works, how to connect, with\na sign-in link into the app — so anyone you point at your relay lands on something that\nexplains itself. **The app is at `/app`** (`/welcome` is an alias for the landing page). A\nrelay running without `site/` serves the app at `/` as before.\n\n### Reaching it from a phone / tablet\n\nWebSockets work from any browser on any device — the app connects to whatever origin served\nit. Two deployment requirements:\n\n1. The relay must be reachable: `HOST=0.0.0.0 PORT=8787 node relay/server.mjs` (LAN) or a\n   proper deploy (small VM, Fly, Railway).\n2. **HTTPS is required on anything that isn't localhost** — browsers only expose\n   `crypto.subtle` (used for E2E decryption) on secure origins, and `wss://` comes with it.\n   Quick test: `cloudflared tunnel --url http://127.0.0.1:8787`. Permanent: Caddy/nginx +\n   Let's Encrypt, or Tailscale Serve for private-to-your-devices access.\n\nThen pair daemons with `--relay https://<your-host>`.\n\n## Accounts: sign up, log in, link devices\n\nTether has ordinary email + password sign-in, and stays end-to-end encrypted while doing it.\nThe trick is that your password never reaches the relay: the browser derives two values from\nit, an *auth hash* (sent, to prove who you are) and a *wrap key* (kept, never sent). The wrap\nkey seals your account encryption key into a blob the relay stores but cannot open. Signing in\ndownloads that blob and unwraps it locally.\n\n- **Sign up** — *Create account* with an email and password. Account id and encryption key are\n  generated in the browser; the relay is handed the auth hash and the sealed key, nothing else.\n- **Sign in** — same email and password on any browser or phone. Each sign-in mints its own\n  client token, so signing in somewhere new never signs you out anywhere else.\n- **Log out** — clears that one browser and calls nothing on the relay. **Paired machines keep\n  running and stay connected**: daemons authenticate with their own Ed25519 device keys, which\n  have nothing to do with browser sessions. Sign back in whenever you like.\n- **Link a device** (optional) — a one-time `TETHERC.…` code, for signing in another browser\n  without typing the password, or for accounts created before email login existed. The relay\n  only ever sees a hash of the code; codes expire in 10 minutes.\n\nEach email is a separate account. Devices, sessions and events are scoped to an account id on\nevery read and write, so two accounts on one relay never see each other's machines.\n\nThe one irrecoverable case: an account with **no** email login, logged out of every browser.\nThen only a link code from a still-signed-in device can get back in. Set an email login from\n*Link a device* if you are in that position.\n\n## Remote approvals\n\nInstall the hooks where you want approval gating (per project, or globally):\n\n```bash\nnode daemon/tetherd.mjs hooks install --settings <project>/.claude/settings.json   # one project\nnode daemon/tetherd.mjs hooks install --settings ~/.claude/settings.json          # everywhere\n```\n\nTwo mechanisms, chosen by how the session was started. Neither ever holds a call the agent\nwould have approved on its own.\n\n**Interactive sessions** (a terminal, Cursor, VS Code — anything you started yourself) use the\n`PermissionRequest` hook. It fires only *after* Claude Code has decided a human must answer, so\nthe agent is already stopped waiting; Tether holds that hook, puts a card in the web UI, and\nreturns your decision. The local prompt stays on screen the whole time — answer at the machine\nor on your phone, first wins. No matcher: every tool that prompts is covered, MCP tools included.\nIf nobody answers within `approvalTimeoutSec` (default 600s) the hook returns nothing and the\nlocal prompt simply remains. `PreToolUse` only observes, to give the mirror context.\n\n**Runs Tether starts itself** (a prompt or new session sent from the web UI) are headless and\nhave no terminal to prompt at, so they get `--permission-prompt-tool` pointing at Tether's own\nMCP server. Claude Code calls it only for decisions it could not make itself — auto mode, allow\nrules and deny rules are all evaluated first — and the answer comes back from the web UI. For\n`AskUserQuestion` the card shows the actual choices and your pick is returned as the answer.\n\n`Stop` / `Notification` hooks make state changes (finished / needs input) instant; sessions\nwithout hooks fall back to a 90s inactivity timer.\n\n**What cannot be answered remotely:** the folder-trust dialog, login and OAuth prompts, sandbox\nnetwork prompts and managed-settings approval. No hook fires for these — they happen outside any\ntool call — so they are shown in the UI but must be answered at the machine. Set\n`remoteApprovals: false` in `~/.tether/config.json` to turn remote approvals off entirely.\n\n## Failure doctrine\n\nEvery mechanism degrades to exactly what happens without Tether: daemon down → sessions run\nlocally and the mirror catches up on reconnect (transcript files are the durable log);\nrelay down → daemon retries with backoff; hook timeout → local prompt.\n\n## Security notes (v1)\n\n- Relay DB holds ciphertext only (AES-256-GCM, per-scope keys via HKDF from the account secret).\n- Daemons authenticate with Ed25519 device keys (challenge/response); clients with a bearer token.\n- The daemon's remote surface is narrow by design: resume/spawn `claude`, answer its own hooks — no generic shell.\n- Account secret sits in browser localStorage and `~/.tether/identity.json` (0600): fine for\n  personal use behind TLS; multi-user hardening is future work (plan M6).\n\n## Status\n\nM0–M4 of the build plan implemented and verified locally (mirror, pairing+E2E, hook\nnotifications, remote approvals, remote prompting incl. new sessions). Not yet done:\nWeb Push to a locked phone (M2 leg), Codex adapter (M5), hardening (M6).\n\n\n## Install\n\n```bash\nnpm i -g @astrakratos/tetherd\ntetherd connect <pairing-code> --relay https://your-relay\n```\n\n`connect` pairs the machine, installs hooks for every agent it finds, registers their transcript\ndirectories, and starts the background service. `tetherd disconnect` reverses all of it and leaves\nthird-party hooks untouched.\n\n## Self-hosting the relay\n\n```bash\nTETHER_DB=/var/lib/tether/relay.sqlite HOST=0.0.0.0 PORT=8787 tetherd relay\n```\n\nPut TLS in front of it — pairing codes carry your encryption key. Give `TETHER_DB` a persistent\nvolume; it is SQLite, so an ephemeral container loses everything on redeploy.\n\n`deploy/` has a systemd unit and a Caddyfile (automatic Let's Encrypt) for a Linux box. On\nmacOS, `tetherd relay-service install` does the same job through launchd.\n\n### Running a relay other people use\n\nA relay open to the internet holds other people's data on a finite disk, so four limits apply.\nAll are environment variables, and all can be turned off for a private relay:\n\n| Variable | Default | What it does |\n|---|---|---|\n| `TETHER_RETAIN_DAYS` | `30` | Events older than this are deleted hourly, along with sessions left empty and settled approvals/prompts. `0` keeps everything forever. |\n| `TETHER_MAX_SESSION_EVENTS` | `50000` | Per-session cap, oldest trimmed first, so one runaway session can't fill the disk ahead of the sweep. |\n| `TETHER_REG_PER_IP_PER_DAY` | `5` | New accounts allowed per IP per day. Reads `X-Forwarded-For`, so put it behind a proxy that sets it. |\n| `TETHER_INVITE_CODE` | unset | When set, registration requires this code. Unset means anyone can sign up. |\n\nThe relay prints its policy on startup, so you can see what a deployment is actually enforcing.\n\n**Retention only limits how far back the web UI can scroll.** The transcripts themselves live in\n`~/.claude/projects` on each user's own machine and are never touched — nobody loses their\nhistory, only remote access to the older part of it. Daemons are told the window on connect so\nthey don't re-upload sessions the relay has already swept.\n\nTwo operational notes. Deleting rows leaves free pages that SQLite reuses, so the file stops\ngrowing but does not shrink; if you migrate an existing relay and want the space back, run\n`sqlite3 $TETHER_DB VACUUM` once. And back the database up — it holds every account, device\npairing and stored event:\n\n```bash\nsqlite3 \"$TETHER_DB\" \".backup /var/backups/tether-$(date +%F).sqlite\"\n```\n\n## Platform support\n\n| | macOS | Linux | Windows |\n|---|---|---|---|\n| Mirror sessions | ✅ | ✅ | ✅ |\n| Agent hooks | ✅ | ✅ | ✅ (named pipe) |\n| Background service | launchd | systemd (user) | Task Scheduler |\n| Answer prompts remotely | ✅ tmux | ✅ tmux | via WSL only |\n\nAnswering a live prompt means typing into a running TUI, which needs tmux. Windows has no\nequivalent that can be driven safely from outside, so on Windows the question is still mirrored —\nyou just answer it on the machine (or run agents under WSL).\n\n\n## Security notes for self-hosting\n\nTwo things to settle before putting a relay on the public internet:\n\n**TLS is required.** The relay speaks plain HTTP and WebSocket, which is fine on `127.0.0.1`\nbut not in public: pairing codes carry your account encryption key. Terminate TLS in front of it\n(Caddy, nginx, or your platform's proxy) and forward the WebSocket upgrade on `/ws`.\n\n**Registration is open.** `POST /api/register` accepts anyone who can reach the relay, so a public\ndeployment lets strangers create accounts on your server. Put it behind a private network, an\ninvite check, or your proxy's auth if that isn't what you want. Login is rate-limited\n(10 attempts / 15 min per email); registration is not.\n\nEverything sensitive lives outside the repo, in `~/.tether/`:\n\n| Path | Contents |\n|---|---|\n| `~/.tether/identity.json` | device keypair and account secret (mode 0600) |\n| `~/.tether/relay.sqlite` | the relay store — ciphertext and routing metadata only |\n| `~/.tether/state.json` | per-file read offsets, so restarts resume rather than replay |\n\n## Configuration\n\nAll optional; nothing is needed to run locally.\n\n| Variable | Default | Use |\n|---|---|---|\n| `TETHER_DB` | `~/.tether/relay.sqlite` | point at a persistent volume when hosting |\n| `PORT` | `8787` | relay listen port |\n| `HOST` | `127.0.0.1` | set `0.0.0.0` when the platform routes to the container directly |\n","readmeFilename":"README.md"}