Skip to content

Writing own client

Egor edited this page Jun 27, 2026 · 3 revisions

In this article, you will find an explained guide about how to build your own client for TuTuck. We are going to do it in Go, but you can choose any other language you like.

Let's start with explaining how the server works.

How server works

First goes SSH handshake, which is pretty easy to implement using golang.org/x/crypto/ssh library. After a successful handshake, your client becomes a channel, where server sends messages.
Since v1.1.0 it sends JSON packets, so your client has to parse those in order to make messages from server look good instead of raw JSON.
For now, client just sends raw text to the server, where its being processed, so you don't have to do any additional things besides sending user input.

There's a lot of other things in TuTuck, but for now, you already know what you need.
Now we can continue to making client.

Keys*

First, we need to generate (or read) keys. You can use core.GenerateKeys()[ref] or implement it yourself, the function is pretty simple. It just generates ssh keys via "ssh-keygen" and puts into ~/.tutuck/.

* It's optional, you can create keys yourself.

Do ssh-keygen -t ed25519 -f ~/.tutuck/key -N ""

Connection

After we got keys, let's connect. To do that, you can use core.ConnectSSH() [ref] or implement it yourself. This one is more advanced, but if you use some library that simplifies work with SSH in your preferred language, it wont be too hard. Now you have a connection, the SSH channel between your client and server. You are ready to get messages!

Getting messages

We can get server output like this

buf := make([]byte, 1024)
for {
	n, _ := conn.Read(buf)
	fmt.Println(string(buf[:n]))
}

At this point you basically got a working read-only client, though now it prints what server sent "as is", so let's continue to parsing.

Parsing.

But to parse everything correctly, your client needs to know what to parse. You need a Packet structure. See the actual structure at pkg.go.dev/github.com/tutuck-org/client-core#Packet

After you've added the structure, we can do parsing this way

// creating new decoder
dec := json.NewDecoder(conn)

// infinite cycle
for {
	var p Packet
	// add error handling here!
	_ := dec.Decode(&p)

	switch p.Type {
		case "error":
			fmt.Printf("%s", p.Content)
		// do pretty much same for other types, or parse those as you want	
	}
}

Great! The output is done. Now we can make the input and sending it to the server.

Input

Just do conn.Write([]byte(text)), where text is what you want to send.

Done. Thanks note

You have just completed writing first working prototype of your client. Now you can make it better with adding more features, improving UI/UX and other stuff. Today we have written a simple version that prints messages to stdout, but you will probably make it more advanced and use some TUI/GUI framework. Whatever you are going to create, you can always open an issue on the server repo with a link to your client so we can add it to the list of clients in README.md or Wiki. Thanks for contributions! Thank you for making TuTuck.

Written by @jvqtil in June 2026