PLEASE ALWAYS USE THE DEVELOP BRANCH
Skywire is a fully open-source, privacy-focused suite of networking tools developed by Skycoin. The public Skywire Network enables this software to be developed and tested in real-world conditions. A few features the Skywire Network provides:
- service discovery for decentralized VPN and SOCKS5 proxy servers
- multi-hop public key–based routing
- a means of accessing and hosting hidden websites
- daily rewards in Skycoin ($SKY) to eligible participants in the Skywire Network
This overview explains Skywire’s key features and network architecture.
Skywire uses dmsg as a control plane to enable all Skywire visors to connect to each other and to deployment services provided by the public Skywire Network (or a user-hosted deployment). DMSG (Read as: D-message) functions as a simple relay system and encrypted transport implementation, facilitating anonymous connections between dmsg clients (i.e., encrypted pubkey-based automatic routing), mediated by the dmsg server. Skywire expands upon this by creating a data plane of direct, secure, encrypted peer-to-peer transports between visors, which may then be used for routes.
A Skywire visor is identified by its public key. Skywire transports are encrypted via the public keys of the visors on each side of the transport. Skywire uses a whitelist system to enable trusted nodes (route setup nodes) to set up routes as calculated by the route finder service through established transports registered in the transport discovery. An automatic transport creation mechanism, enabled by default, is used to establish transports to public visors via STCPR (Skywire TCP Relay) transports, and to visors connected to public visors via SUDPH (Skywire UDP Hole-punching) transports. This auto-transport mechanism is designed to create adequate transports for multi-hop routing.
Skywire routes consist of one or more transports. A Skywire route may not transit the same public key twice, in order to prevent data loops. The Skywire routing system is designed with privacy in mind to defeat data snooping efforts. Packets are uniform in size, stripped of identifying headers, and fuzzed to appear as noise. A visor handling transports where data flows is only aware of the public key of the previous hop and the next hop — not the ultimate source or destination of the packet. These measures significantly mitigate the risk of metadata leakage or traffic analysis. When a transport is trafficking data from multiple sources and destinations, it becomes impossible to perform traffic correlation attacks or related exploits. Another planned feature is route multiplexing, which will multiplex multi-hop routes and permit more bandwidth between the source and destination — similar in concept to BitTorrent.
The name 'visor' was chosen as a less ambiguous term than 'node' to refer to the running Skywire process. The term 'node' is typically reserved as a reference to the hardware on which Skywire is running, in this ecosystem. A Skywire visor participates in transports and provides an interface to applications which can be accessed over or consume routes. The Skywire visor can also be configured to provide a hypervisor web UI for remotely managing a cluster of Skywire visors / nodes, typically referred to as a skyminer.
skywire cli is the primary interface to a running Skywire visor. Skywire cli provides an interface to generate a JSON config file for the Skywire visor, to control visor native applications, and to access data from different Skywire services.
Skywire visors include native VPN and SOCKS5 proxy server and client applications, as well as a messenger application, which are started and managed by the visor. When a server application is started, it registers itself in the service discovery as a proxy server or VPN server. These services may then be consumed by respective client applications via either a direct or multi-hop route. Refer to the documentation for skywire cli proxy and skywire cli vpn for more details.
The skywire dmsg web and skywire dmsg web srv subcommands allow port forwarding over DMSG. Additionally, DmsgWeb provides a resolving SOCKS5 proxy, similar to and inspired by I2P, which permits convenient configuration of a web browser to access DMSG websites. With additional proxy configuration, all browser traffic can be routed through a Skywire SOCKS5 proxy connection. With Skywire’s advanced routing, the already anonymous DMSG utilities can be made even more private by routing them through a Skywire SOCKS5 proxy connection.
SkyNet is the (planned) Skywire counterpoint to DmsgWeb — facilitating port forwarding over Skywire’s peer-to-peer transport types and advanced routing, without transiting a DMSG server or servers.
Skywire enables users to create their own network if desired. The implementation is fully open source. Documentation for making a custom Skywire deployment is here.
The Skywire reward system is the distribution mechanism for Skycoin. Skycoin is not 'mined' as with other cryptocurrencies; rewards in Skycoin ($SKY) are distributed daily to eligible Skywire visors who meet the requirements for obtaining rewards.
Despite the terminology, Skywire visors do not process Skycoin transactions. Skywire visors do not sync the Skycoin blockchain and have no involvement in transaction processing. The only relationship between skywire and the skycoin cryptocurrency is via the reward system acting as the distribution mechanism for Skycoin.
- Commands and Subcommands
- Visor Native Applications
- go install or go run Skywire (go1.24.3)
- Installing Skywire from Release
- Permissions
- Dependencies
- Testing
- Config Gen
- Skywire Configuration in-depth
- Files and folders created by skywire at runtime
- Run skywire visor
- Skycoin Rewards
- Linux Packages
- Docker
- How to create a GitHub release
- Dependency Graph
Documentation is available in the command documentation README:
Note: Visor apps are not executed directly by the user, but hosted by the visor process.
Further documentation can be found in the skywire wiki.
Skywire commands can be executed via go run:
$ go run github.com/skycoin/skywire@develop
┌─┐┬┌─┬ ┬┬ ┬┬┬─┐┌─┐
└─┐├┴┐└┬┘││││├┬┘├┤
└─┘┴ ┴ ┴ └┴┘┴┴└─└─┘
v1.3.29-rc7.0.20250706003615-ed3fbd3aa76d
built with go1.24.3
Available Commands:
visor Skywire Visor
cli Command Line Interface for skywire
svc Skywire services
dmsg DMSG services & utilities
app skywire native applications
Flags:
-b, --bv print runtime/debug.BuildInfo.Main.Version
-d, --info print runtime/debug.BuildInfo
-v, --version version for skywire
The skywire visor can now (as of v1.3.32) run directly with go run when using the default in-process visor native applications configuration
go run github.com/skycoin/skywire@develop cli config gen -br #print the config & output to skywire-config.json
go run github.com/skycoin/skywire@develop visor #uses skywire-config.json by default
The new config omits the "binary" field and the first two arguments app <app-name> :
[
{
"name": "vpn-client",
"args": [
"--dns",
"1.1.1.1"
],
"auto_start": false,
"port": 43
},
{
"name": "skychat",
"args": [
"--addr",
":8001"
],
"auto_start": true,
"port": 1
},
{
"name": "skysocks",
"auto_start": true,
"port": 3
},
{
"name": "skysocks-client",
"args": [
"--addr",
":1080"
],
"auto_start": false,
"port": 13
},
{
"name": "vpn-server",
"auto_start": false,
"port": 44
}
]
For comparison, the external apps launcher config:
[
{
"name": "vpn-client",
"binary": "skywire",
"args": [
"app",
"vpn-client",
"--dns",
"1.1.1.1"
],
"auto_start": false,
"port": 43
},
{
"name": "skychat",
"binary": "skywire",
"args": [
"app",
"skychat",
"--addr",
":8001"
],
"auto_start": true,
"port": 1
},
{
"name": "skysocks",
"binary": "skywire",
"args": [
"app",
"skysocks"
],
"auto_start": true,
"port": 3
},
{
"name": "skysocks-client",
"binary": "skywire",
"args": [
"app",
"skysocks-client",
"--addr",
":1080"
],
"auto_start": false,
"port": 13
},
{
"name": "vpn-server",
"binary": "skywire",
"args": [
"app",
"vpn-server"
],
"auto_start": false,
"port": 44
}
]
To run the visor native applications with external apps configuration, one must first have the skywire binary explicitly installed:
go install github.com/skycoin/skywire@develop
Then, either:
- place the binary in the current working directory where skywire is running OR
- set the
bin_pathin the skywire-config.json to the directory containing the skywire binary
Running a custom skywire visor app requires that the binary for that app exists in the directory specified by "bin_path" in the visor's config
Releases for windows & macOS are available from the release section
Install as a package on debian or arch linux: Package Installation Guide
Binary Releases for many platforms and architectures are provided if none of the other installation methods are preferred.
The following aspects of skywire require elevated or special permissions:
Both VPN client and server require special permissions for network configuration:
The VPN client requires the CAP_NET_ADMIN capability to create and configure TUN/TAP network interfaces.
Method 1: Using setcap (Recommended)
# Grant CAP_NET_ADMIN capability to the skywire binary
sudo setcap cap_net_admin+eip /path/to/skywire
# Verify the capability was set
getcap /path/to/skywire
# Should output: /path/to/skywire cap_net_admin=eipMethod 2: Running as root
sudo skywire visorThe VPN server requires elevated privileges to execute iptables and sysctl commands for:
- Configuring iptables FORWARD policy
- Enabling IP masquerading (NAT)
- Setting IP forwarding (IPv4/IPv6)
- Managing firewall rules for client traffic
Method 1: Configure sudoers (Recommended for systemd services)
# Add to /etc/sudoers.d/skywire-vpn
yourusername ALL=(ALL) NOPASSWD: /usr/sbin/iptables, /usr/sbin/ip6tables, /usr/sbin/sysctlMethod 2: Using setcap for network administration
# Grant CAP_NET_ADMIN and CAP_NET_RAW capabilities
sudo setcap cap_net_admin,cap_net_raw+eip /path/to/skywireMethod 3: Running as root
sudo skywire visorNote for systemd services: When running skywire as a systemd service (non-interactive), pkexec cannot prompt for authentication. Use the sudoers method or run the service as root.
- File system access: Writing to the
localfolder path and default config paths generated by linux/macOS packages or windows .msi installer - System survey: Some aspects require elevated access - only generated if a reward address is set
See mainnet_rules.md for more details about the system survey and eligibility requirements for rewards.
golang
golang or go can be installed with your system package manager on most linux distributions. Alternatively, follow the procedure at go.dev/doc/install to install golang.
Basic setup of the go environment is further described here.
-
git(optional) -
muslandkernel-headers-muslor equivalent - for static compilation
For more information on static compilation, see docs/static-builds.md.
glibcorlibc6unless statically compiled
golangci-lintgoimports-reviserfrom github.com/incu6us/goimports-reviser/v2goimportsfrom golang.org/x/tools/cmd/goimports
Before pushing commits to a pull request, its customary in case of edits to any of the golang source code to run the following:
make format check
make check will run make test as well. To explicitly run tests, use make test.
To run skywire, first generate a config.
skywire cli config gen -birx
-b --bestprotouse the best protocol (dmsg | direct) to connect to the skywire production deployment - recommended-i --ishvcreate a local hypervisor configuration (optional)-r --regenregenerate a config which may already exist, retaining the keys-x --retainhvretain any remote hypervisors which are set in the config (optional)
More options for configuration are displayed with skywire cli config gen --all.
NOTE: If you have installed skywire as a package or via the windows .msi or mac installer, one should additionally include the -p flag - and skywire cli config gen must be run as root.
The skywire visor requires a config file to run. This config is a json-formatted file produced by skywire cli config gen.
The skywire-autoconfig script included with the skywire package handles config generation and config updating for the user who installed the package, as well as restarting the skywire systemd service
Examples of config generation and command / flag documentation can be found in the cmd/skywire-cli/README.md and cmd/skywire-visor/README.md.
The most important flags are noted below.
In order to expose the hypervisor UI, generate a config file with --is-hypervisor or -i flag:
skywire cli config gen -i
After starting up the visor, the UI will be exposed by default on localhost:8000.
Every visor can be controlled by one or more hypervisors. To allow a hypervisor to access a visor, the PubKey of the hypervisor needs to be specified in the configuration file. You can add a remote hypervisor to the config with:
skywire cli config update --hypervisor-pks <public-key>
OR:
skywire cli config gen --hvpk <public-key>
Note: not all of these files will be created by default.
├──skywire-config.json
└─┬local
├── apps-pid.txt
├── node-info.json
├── node-info.sha
├── reward.txt
├── skychat
├── skychat_log.db
├── skysocks
├── skysocks-client
├── skysocks-client_log.db
├── skysocks_log.db
└── transport_logs
├── 2023-03-06.csv
├── 2023-03-07.csv
├── 2023-03-08.csv
├── 2023-03-09.csv
└── 2023-03-10.csv
Some of these files are served via the dmsghttp logserver.
skywire visor hosts apps and is an applications gateway to the Skywire network.
skywire visor requires a valid configuration to be provided.
Note: Root permissions or special capabilities are required for VPN client and VPN server apps. See the Permissions section for details.
Run the visor:
skywire visor -c skywire-config.json
If the default skywire-config.json exists in the current dir, this can be shortened to:
skywire visor
When running VPN applications, ensure proper permissions are configured:
# With setcap configured (recommended):
skywire visor
# Or with sudo if setcap is not configured:
sudo skywire visorskywire visor can be run on Windows. The setup requires additional setup steps that are specified
in the docs if not using the windows .msi.
In the instance that the visor shuts down or stops, it is desirable to restart it automatically. This may be accomplished in a few different ways.
The visor may be run as a systemd service - on linux. The skywire.service does just that, and is provided by the linux packages. skywire.service is configured to run as root.
The visor may be run directly in a (bash / zsh / git-bash) terminal using a while loop with a short timeout between restarts. If one is using the default config path for package-based installation (i.e. starting the visor with the -p flag) it will be required to run the visor as root. If not, omit the -p flag and skip becoming root.
On windows it may be required to start the git-bash terminal as admin or superuser to obtain elevated privileges.
To become root on linux:
su - root
Start the Visor in a while loop
while true ; do skywire visor -pl debug ; sleep 5 ; done
or
while true ; do go run github.com/skycoin/skywire@develop visor -pl debug ; sleep 5 ; done
A few observations when running the visor in the latter way:
- the config is not updated when the binary is updated
- the binary executed by the visor to start the apps is not the same one as is being
go run
To address these two things, it's recommended to first create the human-editable skywire.conf file. This may be done with any path, but for this example, the default path referenced by the autoconfig script included with the linux packages is used.
go run github.com/skycoin/skywire@develop cli config gen -q | sudo tee /etc/skywire.conf
Now, edit /etc/skywire.conf as desired.
Remember to uncomment:
PKGENV=trueBESTPROTO=true
Save the file. Now config gen can be added to the while loop
while true ; do SKYENV=/etc/skywire.conf go run github.com/skycoin/skywire@develop cli config gen -r && go run github.com/skycoin/skywire@develop visor -pl debug ; sleep 5 ; done
To update the binary included with the linux packages so that the visor apps will also be running on the latest commits, it's recommended to go install github.com/skycoin/skywire@develop and then replace the binary provided by the package with that one. The complete command becomes:
while true ; do go install github.com/skycoin/skywire@develop && mv $GOPATH/bin/skywire /opt/skywire/bin/skywire && SKYENV=/etc/skywire.conf skywire cli config gen -r && skywire visor -pl debug ; sleep 5 ; done
Note that the binary at: /opt/skywire/bin/skywire is already symlinked to /usr/bin/skywire by installing the package.
Note: transports should be set up automatically when starting an app in most cases. The user should not need to do this manually.
A Transport represents a bidirectional line of communication between two Skywire Visors:
Transports are automatically established when a client application connects to a server application. Their creation is attempted in the following order:
- stcpr
- sudph
- dmsg
Transports can be manually created. Existing suitable transports will be automatically used by client applications when they are started.
To create a transport, first copy the public key of an online visor from the uptime tracker:
skywire cli ut -o
or service discovery:
skywire cli vpn list #list vpn server keys
skywire cli proxy list #list proxy server keys
Add the transport:
skywire cli visor tp add -t <transport-type> <public-key>
View established transports:
skywire cli visor tp ls
Remove a transport:
skywire cli visor tp rm -i <transport-id>
Note: In most cases, routes are automatically created when applications connect. Manual routing is an advanced feature for specific use cases.
1. App/Consume Rule - Terminates at the local visor for app consumption
2. Forward Rule - Forwards packets to the next hop in a multi-hop route
3. Intermediary Forward Rule - Forwards without app-level routing info
First, list existing routes to find an available route ID:
skywire cli visor route lsCreate an app/consume rule from your visor to a remote visor:
# Get your local public key
LOCAL_PK=$(skywire cli visor pk)
# Get destination visor public key (from service discovery)
REMOTE_PK="02..." # VPN server, proxy server, or any visor
# Create consume rule
skywire cli visor route add a \
-i 1 \ # route ID (increment for each route)
-l $LOCAL_PK \ # local public key
-m 43 \ # local port (app-specific: 43=VPN client, 13=proxy client)
-p $REMOTE_PK \ # remote public key
-q 44 # remote port (44=VPN server, 3=proxy server)Common app port mappings:
- 1 - skychat
- 3 - skysocks (proxy server)
- 13 - skysocks-client (proxy client)
- 43 - vpn-client
- 44 - vpn-server
View app ports:
skywire cli visor app lsImportant: Apps will automatically use manually created routes if the route's local/remote PK and ports match the app's connection requirements.
Example - VPN client using manual route:
# 1. Create route with local port 43, remote port 44
skywire cli visor route add a -i 1 -l $LOCAL_PK -m 43 -p $VPN_SERVER_PK -q 44
# 2. Start VPN client - it will automatically use route ID 1
skywire cli vpn start $VPN_SERVER_PKThe VPN client connects from port 43 → server port 44, matching the route rule, so it's used automatically.
Multi-hop routes require coordination between visors. This example creates a 2-hop route: A → B → C
On Visor A (source):
# Create forward rule to visor B
skywire cli visor route add c \
-i 1 \
-j 2 \ # next route ID (on visor B)
-k $TRANSPORT_ID \ # transport ID to visor B
-l $VISOR_A_PK \
-m 43 \
-p $VISOR_C_PK \ # final destination
-q 44On Visor B (intermediary):
# Create intermediary forward rule to visor C
skywire cli visor route add b \
-i 2 \
-j 3 \ # next route ID (on visor C)
-k $TRANSPORT_ID # transport ID to visor COn Visor C (destination):
# Create consume rule
skywire cli visor route add a \
-i 3 \
-l $VISOR_C_PK \
-m 44 \
-p $VISOR_A_PK \
-q 43Get transport IDs for multi-hop routing:
# List all transports
skywire cli visor tp ls
# Find specific transport by remote public key
skywire cli visor tp ls | grep $REMOTE_PKQuery the route finder to discover available multi-hop paths:
# Find routes between two visors
skywire cli visor route find $SOURCE_PK $DEST_PK
# With custom hop limits
skywire cli visor route find $SOURCE_PK $DEST_PK --min 2 --max 3
# Find routes from local visor to destination (auto-detects local PK)
skywire cli visor route find $DEST_PKThe route finder returns the optimal path, which you can then configure manually using the commands above.
List all routing rules:
skywire cli visor route lsView specific route details:
skywire cli visor route ls -i <route-id>Remove a routing rule:
skywire cli visor route rm <route-id>Routes not being used:
- Verify local/remote ports match app requirements (
skywire cli visor app ls) - Check transports exist to the next hop (
skywire cli visor tp ls) - Ensure route IDs are sequential and unique
- Verify public keys are correct
Multi-hop routes failing:
- Each intermediary must have the correct transport ID to the next hop
- Route IDs must chain correctly across visors
- Keep-alive duration may need adjustment for long routes (
--keep-alive 60s)
The following documentation exists for vpn server / client setup and usage:
An example using the vpn with skywire cli:
skywire cli vpn list
This will query the service discovery for a list of vpn server public keys. sd.skycoin.com/api/services?type=vpn
Sample output:
02836f9a39e38120f338dbc98c96ee2b1ffd73420259d1fb134a2d0a15c8b66ceb
0289a464f485ce9036f6267db10e5b6eaabd3972a25a7c2387f92b187d313aaf5e
03cad59c029fc2394e564d0d328e35db17f79feee50c33980f3ab31869dc05217b
02cf90f3b3001971cfb2b2df597200da525d359f4cf9828dca667ffe07f59f8225
03e540ddb3ac61385d6be64b38eeef806d8de9273d29d7eabb8daccaf4cee945ab
...
Select a key and start the vpn with:
skywire cli vpn start <public-key>
View the status of the vpn:
skywire cli vpn status
Check your ip address with ip.skywire.dev.
Note: ip.skycoin.com will only show your real ip address, not the ip address of the vpn connection.
Stop the vpn:
skywire cli vpn stop
Note: killswitch may be configured for the vpn - see skywire cli config gen --all help menu or documentation.
The following wiki documentation exists on the SOCKS5 proxy:
The main difference between the vpn and the socks5 proxy is that the proxy is configured per application while the vpn wraps the connections for the whole machine.
The socks client usage (from skywire cli) is similar to the vpn, though the skywire cli subcommands and flags do not currently match from the one application to the other. This will be rectified.
To use the SOCKS5 proxy client via skywire cli:
skywire cli proxy list
This will query the service discovery for a list of visor public keys which are running the proxy server. sd.skycoin.com/api/services?type=proxy
Sample output:
031a924f5fb38d26fd8d795a498ae53f14782bc9f036f8ff283c479ac41af95ebd
024fdf44c126e122f09d591c8071a7355d4be9c561f85ea584e8ffe4e1ae8717f7
03ae05142dcf5aad70d1b58ea142476bac49874bfaa67a1369f601e0eb2f5842df
0313a76e2c331669a0cb1a3b749930881f9881cca89b59ee52365d1c15141d9d83
03022fa8a0c38d20fae9335ef6aa780f5d762e1e161e607882923dc0d5a890f094
03e4b6326f9df0cff1372f52906a6d1ee03cf972338d532e17470e759362e45c87
0230689d26e5450e8c44faaba91813b7c2b00c1add3ad251e2d62ecca8041a849d
036ae558d5e6c5fc73cb6a329cb0006b4f659ecf9ae69c9e38996dfb65b1fb1c45
03a35c742ed17506834235b2256bb2b0a687de992e5ded52ca4d54fba3b00b8dbe
0259721a9e79e91ce8bc94bad52a6a381d50fcb05aaadc2c99201fd137fb71dfde
...
Select a key and start the proxy with:
skywire cli proxy start --pk <public-key>
View the status of the proxy:
skywire cli proxy status
Check the ip address of the connection; for example, using curl via the socks5 proxy connection:
curl -Lx socks5h://127.0.0.1:1080 http://ip.skycoin.com/ | jq
The connection may be consumed in a web browser via direct proxy configuration in browsers which support it, or using such extensions as foxyproxy.
The connection may also be consumed in the terminal by setting ALL_PROXY environmental variable, or via the specific method used by a certain application.
Examples of ssh over the socks5 proxy:
Using openbsd-netcat:
ssh user@host -p 22 -o "ProxyCommand=nc -X 5 -x 127.0.0.1:1080 %h %p"
Using ncat from nmap:
ssh user@host -p 22 -o "ProxyCommand=ncat --proxy-type socks5 --proxy 127.0.0.1:1080 %h %p"
Stop the socks5 proxy client:
skywire cli proxy stop
Running skywire on eligible hardware can earn rewards in skycoin. Currently, only package-based linux installations are supported for rewards. Review the mainnet rules article for the details.
Set a reward address:
skywire cli reward <skycoin-address>
Visors meeting uptime and eligability requirements will recieve daily skycoin rewards for up to 8 visors per location / ip address.
All Linux packages provide a virtually identical installation, helper scripts, and systemd services regardless of the linux distro.
Consider the skywire PKGBUILD as a reference for building and installing skywire on any linux distribution.
Debian packages are maintained for skywire, as well as several build variants for archlinux.
It's recommended to install the debian packages from the apt repo - see the instructions here:
https://deb.skywire.skycoin.com/
Installing skywire-bin from the AUR will install the release binaries provided by the release section of this repository:
yay -S skywire-bin
To build the debian packages using the release binaries:
yay --mflags " -p cc.deb.PKGBUILD " -S skywire-bin
Installing skywire from the AUR will compile binaries using the source archive for the latest version release:
yay -S skywire
Build the skywire Arch Linux package from git sources to the latest commits on the develop branch:
yay --mflags " -p git.PKGBUILD " -S skywire
For docker-specific documentation, see: DOCKER.md
- Make sure that
gitand goreleaser are installed. - Checkout to a commit you would like to create a release against.
- Run
go mod vendorandgo mod tidy. - Make sure that
git statusis in clean state. Commit all vendor changes and source code changes. - Uncomment
draft: truein.goreleaser.ymlif this is a test release. - Create a
gittag with desired release version and release name:git tag -a 0.1.0 -m "First release", where0.1.0is release version andFirst releaseis release name. - Push the created tag to the repository:
git push origin 0.1.0, where0.1.0is release version. - ̶I̶s̶s̶u̶e̶ ̶a̶ ̶p̶e̶r̶s̶o̶n̶a̶l̶ ̶G̶i̶t̶H̶u̶b̶ ̶a̶c̶c̶e̶s̶s̶ ̶t̶o̶k̶e̶n̶.̶
- ̶R̶u̶n̶ ̶
̶G̶I̶T̶H̶U̶B̶_̶T̶O̶K̶E̶N̶=̶y̶o̶u̶r̶_̶t̶o̶k̶e̶n̶ ̶m̶a̶k̶e̶ ̶g̶i̶t̶h̶u̶b̶-̶r̶e̶l̶e̶a̶s̶e̶̶ - Check the created GitHub release.
made with goda
go run github.com/loov/goda@latest graph github.com/skycoin/skywire/... | dot -Tsvg -o docs/skywire-goda-graph.svg