Repository: shuttle-hq/synth (language: rust)

Issue:
UX: Make synth init obsolete
**Required Functionality**
Currently, users must initialize a "workspace" before using synth to generate data. The rationale for this was that synth would be able to write files for both import and possibly generation (e.g. with #33) and having a directory for itself would reduce the risk of accidentally overwriting files. However, both requiring a call to "synth init" and the generated directories, even if empty, make it harder to set up tests and worsen the user experience.

**Proposed Solution**
Recognizing that we put the baby out with the bathwater, we should not require user interaction unless there's a problem. So at the very least we could remove the synth init command and subsequent check for the `.synth` directory and instead add a prompt to ask the user whenever overwriting a file. Even better, we could record the files and creation timestamp whenever synth creates a new file and not issue a prompt when a file of that list gets overwritten. We should however keep the list of generated files somewhat short; storing up to 1000 files should be enough for everybody (famous last words). When the list gets full, we could check for removed files, otherwise remove the oldest entries.  

**Use case**
Improve user experience, simplify testing and reproducibility (because the tests no longer need to clean up `.synth` folders).


Discussion / hints:
I should note that it's just an idea at this moment, and we need some discussion to validate the concept.
I have hacked together a [quick example](https://github.com/brokad/synth/tree/fork/no-init) of what that would look like in the hope it will help fuel the discussion. Feel free to give it a quick spin.

`synth init` is mostly redundant. It was introduced as a quick and dirty way of "locking" a directory to belong to `synth` (in order to prevent inadvertent overwrites on potentially destructive actions like `synth import`). Maybe we also thought of it as an "anchor" to specify the root of a repository of synth schema files? I however cannot find references to that in the code: I believe the current implementation just checks it exists at `$PWD` and moves on.

In the branch, I have simply added more consistency to the treatment of paths in CLI arguments to compensate for the absence of `synth init`. For example, you can run
```shell
$ synth generate examples/bank/bank_db/users.json
```
or the equivalent
```shell
$ cd examples/bank/bank_db; synth generate users.json
```
to generate only the users data. Or you can run
```shell
$ synth generate examples/bank/bank_db/
```
to generate the whole bank_db example.

On import, synth will prompt for confirmation before overwriting existing files but otherwise behaves as before (minus `synth init` step).
```shell
$ mkdir -p /tmp/test_import; synth generate examples/bank/bank_db | synth import /tmp/test_import
```
Thanks for bringing this up - it is a slightly contentious issue.

So first of all - what do we have now. When you run `synth init` a sub-directory `.synth` is created which marks the parent directory as a `workspace` for synth. This also creates an as of now empty `config.toml`.

## A comparison with other tools

This concept of workspaces is clearly not original - to give an example `terraform` has a similar concept when you run `terraform init` initialising a directory and creating a marker sub-directory or file. The same is true for some IDEs like IntelliJ, which creates `.idea` sub-directory when you create a project. This too serves as a marker and holds metadata about the project.

Other tools take slightly different approaches - take `kubectl` for example and `gcloud`. They have a global state in `~/.config` (or something like that) which is 'global' for the user. 

They key difference between the two paradigms is that the former are associated deeply with the underlying files, while the latter do not care. For example, `terraform` cares deeply about the flles in a given subdirectory which is literally a textual representation of your infastructure where as `gcloud` couldn't care less about the file in `$PWD` when a `gcloud` command is used. Furthermore, there is configuration that is deeply coupled with `$PWD` in the case of tools like `terraform` or your IDE. It makes sense that you don't want to manually be switching up config constantly. Finally both `terraform` and IDEs have free reign to modify files (in a sensible way) in their respective workspaces, which is also the same for `synth`; by not prompting on file modification and deletion (as @brokad proprosed) and having well defined behaviour they offer a better user experience.

## The case for state

Okay so all these tools we've talked about have some context of state. From the local `tfstate` to your IDE's settings. `synth` currently doesn't have state.

Well this is almost true - `synth` does have state in the status of telemetry being enabled or not. This is held in an OS specific config directory similar to `.config/synth`. I'm not sure why that decision was made (i think it should be on a per-workspace case now) since some users may want to share telemetry data on some workspaces and not in others (which they may consider sensitive).

Furthermore as the project is built out we will have more state to deal with which *will* be workspace specific. I am not going to elaborate too much here, as much of this is TBD, but for example:
- credentials for generating on a synth cluster
- saving credentials for connecting with a database (so you don't always specify them on the command line)
- ML models (weights) that are generated on an ad-hoc basis as per conversations with @fretz12 about understanding binary payload distributions
- holding metadata across generation sessions (i.e. if generation is aborted and then resumed)

and many more.

## The software engineering experience

Finally w.r.t quality of life for our end users, I think a little structure and opinionated design can help users implicitly pick up what we believe are best practices. This is mostly opinion, but a few points are:
- By arranging `synth` files into workspaces, developers will always know where those files are code repositories won't get littered with random files all over the place
- Diffs and PRs will be more localised where they pertain change of a data model
- Developers won't accidentally put random text files, scratch files, temporary files or whatever in a directory which is dedicated to their data models

## tldr

- `synth` is tightly coupled to the contents of a directory, thus the concept of a workspace can provide a superior user experience as the binary has free reign in that directory.
- `synth` will eventually have workspace level state, and that state should be stored in the workspace directory. `synth init` is currently initialisation of that state
- organising synth schema files in a workspace hierarchy will provide a better SE experience
 

Thanks @christoshadjiaslanis for outlining your thinking on this! It clears up some of the confusion I had about why this exists in the first place :smile:

It seems like the decision to have `synth init` is tied to the desire to have a notion of project or workspace and - later on - to a local state. Both of which seem important to the long-term roadmap. In that way, `synth init` is there for future-proofing and force users to think in terms of workspace/project.

I wonder if it would be possible still to allow users to run simple Synth schema files outside of workspaces. For example, running documentation snippets like [this one](https://getsynth.github.io/synth/content/same-as#example-1) without having to setup a new workspace. Maybe mounting the workspace type workflows under a subcommand like `synth workspace` and otherwise leaving the top-level CLI able to deal with individual JSON files outside of workspaces?
Another thing that could work is allowing to generate from individual files (viewed as regular `Content`) when the `.synth` directory is not found at `$PWD` and otherwise behaving as currently (traversing a given path and assembling into a `Namespace`).

Any thoughts @christoshadjiaslanis?
@brokad these seem like good ideas. Basically it boils down to:
- if we run `synth generate my_file.json`, treat `my_file.json` as a regular `Content` (we can use the code from the playground here) 
- If it is pointed to a directory, treat that directory as a `Namespace`

So I guess the next step if this line of inquiry would be to ask:
- what happens on import outside a workspace?
- what happens if `my_file.json` above refers to some content that requires state (hence requiring a workspace).
> - if we run synth generate my_file.json, treat my_file.json as a regular Content (we can use the code from the playground here)
> - If it is pointed to a directory, treat that directory as a Namespace

Indeed.

> what happens on import outside a workspace?

As @llogiq suggested above, nothing special. We could prompt for user confirmation before overwriting existing files, or we could proceed as we do now - i.e. outright refuse the operation if the target path is non-empty/exists.

> what happens if my_file.json above refers to some content that requires state (hence requiring a workspace).

I'm not sure what you mean. Can you give me an example of something like this?
> I'm not sure what you mean. Can you give me an example of something like this?

Not currently - it is more thinking ahead..

I'll play around with your fork tomorrow and get back to you :)
@brokad thanks for your work on the fork.

After playing around with it - it is clear that not having workspaces offers a better UX as of today. In the future, if we have some concept of namespace/workspace specific state to hold things like model weights or database credentials, we can add workspaces back in.

Next steps:
- [ ] Merge relevant parts of `fork/no-init` into `getsynth/synth:master`
- [ ] Update the documentation to not mention workspaces any more
- [ ] Update `asciinema` on website to no longer have `synth init`
- [ ] Update tutorial content to no longer mention workspaces
- [ ] Create new release

Fix patch:
diff --git a/.github/workflows/synth-mongo.yml b/.github/workflows/synth-mongo.yml
index 3d15211c..3040ebcb 100644
--- a/.github/workflows/synth-mongo.yml
+++ b/.github/workflows/synth-mongo.yml
@@ -27,7 +27,6 @@ jobs:
       - run: |
           echo "Running generate test"
           cd synth/testing_harness/mongodb/synth
-          synth init
           synth generate hospital --size 100 --to mongodb://localhost:27017/hospital
           cd ..
           COLLECTIONS=(hospitals doctors patients)
diff --git a/.github/workflows/synth-mysql.yml b/.github/workflows/synth-mysql.yml
index ec2f65ae..69f06e43 100644
--- a/.github/workflows/synth-mysql.yml
+++ b/.github/workflows/synth-mysql.yml
@@ -71,7 +71,6 @@ jobs:
       - run: |
           echo "Running generate test"
           cd synth/testing_harness/mysql
-          synth init || true
           synth generate hospital_master --to ${{ env.DB_SCHEME }}://${{ env.MYSQL_USER }}:${{ env.MYSQL_ROOT_PASSWORD }}@${{ env.MYSQL_HOST }}:${{ env.MYSQL_PORT }}/${{ env.MYSQL_DATABASE }} --size 30
           bash "${GITHUB_WORKSPACE}/.github/workflows/scripts/validate_mysql_gen_count.sh"
       ## Clear out and repopulate DB
diff --git a/.github/workflows/synth-postgres.yml b/.github/workflows/synth-postgres.yml
index 960a01bc..c9cb96a0 100644
--- a/.github/workflows/synth-postgres.yml
+++ b/.github/workflows/synth-postgres.yml
@@ -42,7 +42,6 @@ jobs:
       - run: |
           echo "Running generate test"
           cd synth/testing_harness/postgres
-          synth init || true
           synth generate --size 10 hospital_master > hospital_data_generated.json
           diff hospital_data_generated.json hospital_data_generated_master.json || exit 1
       - run: |
diff --git a/README.md b/README.md
index f0561b44..dfe6120c 100644
--- a/README.md
+++ b/README.md
@@ -58,13 +58,9 @@ For more installation options, check out the [docs](https://getsynth.com/docs/ge
 
 ### Building a data model from scratch
 
-To start generating data without having a source to import from, you need to first initialise a workspace using `synth init [opt path]` (if no optional path is specified, the current directory will be used):
+To start generating data without having a source to import from, you need to add Synth schema files to a namespace directory:
 
-```bash
-$ synth init /some/path
-```
-
-Inside the workspace we'll create a namespace for our data model and call it `my_app`:
+To get started we'll create a namespace directory for our data model and call it `my_app`:
 
 ```bash
 $ mkdir my_app
@@ -129,13 +125,7 @@ $ synth generate my_app/ --size 2 | jq
 
 If you have an existing database, Synth can automatically generate a data model by inspecting the database.
 
-To get started, initialise your Synth workspace locally:
-
-```bash
-$ mkdir synth_workspace && cd synth_workspace && synth init
-```
-
-Then use the `synth import` command to build a data model from your Postgres or MongoDB database:
+You can use the `synth import` command to automatically generate Synth schema files from your Postgres, MySQL or MongoDB database:
 
 ```bash
 $ synth import tpch --from postgres://user:pass@localhost:5432/tpch
diff --git a/docs/docs/getting_started/cli.md b/docs/docs/getting_started/cli.md
index c4408b2d..98d9563a 100644
--- a/docs/docs/getting_started/cli.md
+++ b/docs/docs/getting_started/cli.md
@@ -9,32 +9,18 @@ title: Command-line
 
 ---
 
-### Command: init
-
-Usage: `synth init`
-
-This is the first command that should be run for any new or existing when starting out with Synth. 
-This initialises the workspace and  sets up all the local data necessary to run Synth.
-A `.synth/` subdirectory is created that is typically not committed to version control.
-
-This command is always safe to run multiple times though subsequent runs
-may give errors. This command will never erase your workspace.
-
----
-
 ### Command: import
 
 Usage: `synth import [OPTIONS] <namespace>`
 
-Synth can create namespaces from different data sources using the `synth import` command.
-Accidentally running `synth import` on an existing namespace is safe - the operation will fail.
+Synth can create schema files from different data sources using the `synth import` command.
+Accidentally running `synth import` on an existing directory is safe - the operation will fail.
 
-If a subdirectory for a given namespace does not exist in your workspace, Synth will create it.
+If a subdirectory for a given namespace does not exist, Synth will create it.
 
 #### Argument
 
-- `<namespace>` - The desired path to the imported namespace directory. Can only
-  be a path relative to the current (initialised) workspace root.
+- `<namespace>` - The path to the namespace directory into which to save schema files. The directory will be created by `synth`.
   
 #### Options
  
@@ -54,14 +40,13 @@ If a subdirectory for a given namespace does not exist in your workspace, Synth
 
 Usage: `synth generate [OPTIONS] <namespace>`
 
-The `synth generate` command will generate data for a given namespace. This will not mutate anything in the underlying configuration.
+The `synth generate` command will generate data from a collection of schema files.
 
 If there is a misconfiguration in your schema (for example referring to a field that does not exist), `synth generate` will exit with a non-zero exit code and output an error message to help you understand which part of the schema is misconfigured.
 
 #### Argument
 
-- `<namespace>` - The path to the namespace you wish to generate data for. Can
-  only be a path relative to the current (initialised) workspace root.
+- `<namespace>` - The path to the namespace directory from which to load schema files.
   
 #### Options
 
diff --git a/docs/docs/getting_started/core-concepts.md b/docs/docs/getting_started/core-concepts.md
index 743b6464..bcdf818a 100644
--- a/docs/docs/getting_started/core-concepts.md
+++ b/docs/docs/getting_started/core-concepts.md
@@ -4,25 +4,6 @@ title: Core concepts
 
 This section covers the core concepts found in Synth.
 
-## Workspaces
-
-Workspaces are marked by the existence of a `.synth/` subdirectory. A workspace
-represents a set of synthetic data namespaces managed by Synth.
-
-A workspace can have *zero or more namespaces*. Each namespace is represented as
-a subdirectory of the workspace. All information pertaining to a workspace is in
-its directory, there is no external configuration.
-
-Below is an example directory structure for a workspace with a single
-namespace, `my_namepace`.
-
-```
-├── .synth
-└── my_namespace
-    ├── my_collection_1.json
-    └── my_collection_2.json
-``` 
-
 ## Namespaces
 
 The **namespace** is the top-level abstraction in Synth. Namespaces are the
@@ -30,22 +11,19 @@ equivalent of traditional [schemas][sql-schemas] in the world of relational
 databases likes PostgreSQL. [References](#field-references) can exist between
 fields in a given namespace, but never across namespaces.
 
-Namespaces are represented as sub-directories in a workspace. For example, a
-workspace with single namespace `some_namespace` would have the following
+Namespaces are simply directories from which `synth` reads a collection of
+schema files. For example, a namespace `blog` could have the following
 structure:
 
 ```
-├── .synth
-└── my_namespace
+└── blog/
+    ├── users.json
+    └── posts.json 
 ``` 
 
-You can have as many namespaces as you like within a workspace:
-
-```
-├── .synth
-├── some_namespace
-└── some_other_namespace 
-```
+Any file whose extension is `.json` in a namespace directory will be opened by
+the [`synth generate`][synth-generate] subcommand and considered part of the
+namespace's schema.
 
 ## Collections
 
@@ -54,27 +32,21 @@ their name and correspond to [tables][sql-tables] in the world of relational
 databases. Strictly speaking, collections are a super-set of tables as they are
 in fact arbitrarily deep JSON document trees.
 
-Collections are represented in a workspace as JSON files. The *name* of a
-collection (the way it is referred to by [`synth`][synth]) is its filename
+Collections are represented in a namespace directory as JSON files. The *name*
+of a collection (the way it is referred to by [`synth`][synth]) is its filename
 without the extension. For example the file `bank/transactions.json` defines a
 collection named `transactions` in a namespace `bank`.
 
 For a more comprehensive example, let's imagine our namespace `bank` has a
-collection `transactions` and another collection `users`. The workspace
+collection `transactions` and another collection `users`. The directory
 structure then looks like this:
 
 ```
-├── .synth
-└── bank
+└── bank/
     ├── transactions.json
     └── users.json 
 ```
 
-Collections inside a given namespace need to have unique names. You can however
-have the same collection name in different namespaces. For
-example `bank/transactions.json` and `forex/transactions.json` is a valid
-workspace.
-
 Collections must be valid instances of the [`synth` schema][schema] that
 describe an array. This means at the top-level all collections must
 be [array generators][array-generators].
diff --git a/docs/docs/getting_started/hello-world.md b/docs/docs/getting_started/hello-world.md
index af2f8018..f15635b1 100644
--- a/docs/docs/getting_started/hello-world.md
+++ b/docs/docs/getting_started/hello-world.md
@@ -2,37 +2,23 @@
 title: Hello world
 ---
 
-After installing [`synth`][synth], the next step is to create a **workspace**. 
+After installing [`synth`][synth], the next step is to create a **namespace**. 
 
-Workspaces are directories in your filesystem that [`synth`][synth] uses to read your schemas from. Currently [`synth`][synth] reads schemas written in a specialized JSON data model. You can find out everything there is to know about [`synth`][synth] schemas in the [Generators][generators] section or in the [Schema][schema] section. In this section we will show you how to set up a simple "hello world" data generator.
+Namespaces are directories in your filesystem that [`synth`][synth] uses to read your schemas from. Currently [`synth`][synth] reads schemas written in a specialized JSON data model. You can find out everything there is to know about [`synth`][synth] schemas in the [Generators][generators] section or in the [Schema][schema] section. In this section we will show you how to set up a simple "hello world" data generator.
 
-To create and initialise a workspace called `synth_workspace` in your current working directory, run:
+To create a namespace, just create a new directory:
 
 ```bash
-mkdir synth_workspace && cd synth_workspace && synth init
-```
-
-:::note Note
-
-The command [`synth init`][synth-init] creates a marker directory called `.synth` in the directory where it is run. This marker directory acts as simply an anchor to tell [`synth`][synth] that this is a workspace.
-:::
-
-Next we need to create a **namespace**. Namespaces are directories in an
-initialized [`synth`][synth] workspace. All the schema files in a given
-namespace are collated and compiled together at runtime.
-
-Let's create a namespace called `my_namespace`:
-
-```bash
-mkdir my_namespace
+mkdir hello_synth
 ```
 
 Finally, we need to add a **collection** to our namespace. Collections describe
 the "shape" of the data we want to generate. They are individual JSON files
-within a namespace written according to the [`synth` schema][generators].
+within a namespace directory written according to
+the [`synth` schema][generators].
 
-To create a collection called "dummy" in our namespace, simply copy/paste the content of the following example in a file
-at `synth_workspace/my_namespace/dummy.json`:
+To create a collection called "say_hello" in our namespace, simply copy/paste the content of the following example in a file
+at `hello_synth/say_hello.json`:
 
 ```json synth
 {
@@ -56,9 +42,11 @@ button that lets you preview how [`synth`][synth] would output the corresponding
 data.
 
 Finally, run
+
 ```bash
-synth generate my_namespace/
+synth generate hello_synth/
 ```
+
 and you should see an output very close to the output of the snippet.
 
 ## Where to go from here
diff --git a/synth/benches/bench.rs b/synth/benches/bench.rs
index 24bfe9f3..79088972 100644
--- a/synth/benches/bench.rs
+++ b/synth/benches/bench.rs
@@ -3,18 +3,6 @@
 
 use synth::cli::{Args, Cli};
 
-fn bench_init() {
-    async_std::task::block_on(
-        #[allow(unused_must_use)]
-        async {
-            Cli::new(Args::Init { init_path: None })
-                .unwrap()
-                .run()
-                .await;
-        },
-    )
-}
-
 fn bench_generate_1_to_stdout() {
     bench_generate_n_to_stdout(1);
 }
@@ -43,7 +31,6 @@ fn bench_generate_n_to_stdout(size: usize) {
 }
 
 iai::main!(
-    bench_init,
     bench_generate_1_to_stdout,
     bench_generate_100_to_stdout,
     bench_generate_10000_to_stdout,
diff --git a/synth/src/cli/mod.rs b/synth/src/cli/mod.rs
index 36191798..64f1f1cf 100644
--- a/synth/src/cli/mod.rs
+++ b/synth/src/cli/mod.rs
@@ -15,8 +15,7 @@ use crate::cli::import::SomeImportStrategy;
 use crate::cli::store::Store;
 use anyhow::{Context, Result};
 
-use std::fs::File;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use structopt::StructOpt;
 
 use crate::cli::telemetry::TelemetryClient;
@@ -81,6 +80,11 @@ impl Cli {
 
     pub async fn run(self) -> Result<()> {
         match self.args {
+	    Args::Init { .. } => {
+		with_telemetry("init", &self.telemetry, || {
+		    Ok(())
+		})
+	    },
             Args::Generate {
                 ref namespace,
                 ref collection,
@@ -104,9 +108,6 @@ impl Cli {
             } => with_telemetry("import", &self.telemetry, || {
                 self.import(namespace.clone(), collection.clone(), from.clone())
             }),
-            Args::Init { ref init_path } => {
-                with_telemetry("init", &self.telemetry, || self.init(init_path.clone()))
-            }
             Args::Telemetry(telemetry) => {
                 match telemetry {
                     TelemetryCommand::Enable => {
@@ -132,83 +133,12 @@ impl Cli {
         }
     }
 
-    fn init(&self, init_path: Option<PathBuf>) -> Result<()> {
-        let base_path = match init_path {
-            Some(path) => std::fs::canonicalize(".")?.join(path),
-            None => std::fs::canonicalize(".")?,
-        };
-        match self.workspace_initialised_from_path(&base_path) {
-            // need to check workspace in base_path
-            true => Err(anyhow!("Workspace already initialized!")),
-            false => {
-                let workspace_dir = ".synth";
-                let result =
-                    std::fs::create_dir_all(base_path.join(workspace_dir)).with_context(|| {
-                        format!(
-                            "Failed to create working directory at: {} during initialization",
-                            base_path.join(workspace_dir).to_str().unwrap()
-                        )
-                    });
-                let config_path = self.get_synth_config_file(base_path);
-                match result {
-                    Ok(()) => {
-                        File::create(config_path.as_path()).with_context(|| {
-                            format!(
-                                "Failed to create config file at: {} during initialization",
-                                config_path.to_str().unwrap()
-                            )
-                        })?;
-                        Ok(())
-                    }
-                    Err(ref e)
-                        if e.downcast_ref::<std::io::Error>().unwrap().kind()
-                            == std::io::ErrorKind::AlreadyExists =>
-                    {
-                        File::create(config_path.as_path()).with_context(|| {
-                            format!(
-                                "Failed to initialize workspace at: {}. File already exists.",
-                                config_path.to_str().unwrap()
-                            )
-                        })?;
-                        Ok(())
-                    }
-                    _ => result,
-                }
-            }
-        }
-    }
-
-    fn get_synth_config_file(&self, base_path: PathBuf) -> PathBuf {
-        base_path.join(".synth").join("config.toml")
-    }
-
-    fn workspace_initialised(&self) -> bool {
-        PathBuf::from(".synth").join("config.toml").exists()
-    }
-
-    fn workspace_initialised_from_path(&self, init_path: &Path) -> bool {
-        init_path.join(".synth").join("config.toml").exists()
-    }
-
     fn import(
         &self,
         path: PathBuf,
         collection: Option<Name>,
         import_strategy: Option<SomeImportStrategy>,
     ) -> Result<()> {
-        if !self.workspace_initialised() {
-            return Err(anyhow!(
-                "Workspace has not been initialised. To initialise the workspace run `synth init [optional path]`."
-            ));
-        }
-
-        if !path.is_relative() {
-            return Err(anyhow!(
-		"The namespace path `{}` is absolute. Only paths relative to an initialised workspace root are accepted.",
-		path.display()
-	    ));
-        }
-
         // TODO: If ns exists and no collection: break
         // If collection and ns exists and collection exists: break
         if let Some(collection) = collection {
@@ -227,7 +157,7 @@ impl Cli {
             }
         } else if self.store.ns_exists(&path) {
             Err(anyhow!(
-                "The namespace at `{}` already exists. Will not import into an existing namespace.",
+                "The directory at `{}` already exists. Will not import into an existing directory.",
                 path.display()
             ))
         } else {
@@ -245,11 +175,6 @@ impl Cli {
         to: Option<SomeExportStrategy>,
         seed: u64,
     ) -> Result<()> {
-        if !self.workspace_initialised() {
-            return Err(anyhow!(
-                "Workspace has not been initialised. To initialise the workspace run `synth init [optional path]`."
-            ));
-        }
         let namespace = self
             .store
             .get_ns(ns_path.clone())
@@ -270,19 +195,18 @@ impl Cli {
 #[derive(StructOpt)]
 #[structopt(name = "synth", about = "synthetic data engine on the command line")]
 pub enum Args {
-    #[structopt(about = "Initialise the workspace")]
+    #[structopt(about = "(DEPRECATED). For backward compatibility and is a no-op.")]
     Init {
-        #[structopt(parse(from_os_str), help = "name of directory to initialize")]
-        init_path: Option<PathBuf>,
+	init_path: Option<PathBuf>
     },
     #[structopt(about = "Generate data from a namespace", alias = "gen")]
     Generate {
         #[structopt(
-            help = "the namespace directory from which to generate",
+            help = "The namespace directory from which to read schema files",
             parse(from_os_str)
         )]
         namespace: PathBuf,
-        #[structopt(long, help = "the specific collection from which to generate")]
+        #[structopt(long, help = "The specific collection from which to generate")]
         collection: Option<Name>,
         #[structopt(long, help = "the number of samples", default_value = "1")]
         size: usize,
@@ -305,7 +229,7 @@ pub enum Args {
     #[structopt(about = "Import data from an external source")]
     Import {
         #[structopt(
-            help = "The namespace directory into which to import",
+            help = "The namespace directory into which to save imported schema files",
             parse(from_os_str)
         )]
         namespace: PathBuf,
@@ -337,8 +261,6 @@ pub enum TelemetryCommand {
 #[cfg(test)]
 pub mod tests {
     use super::*;
-    use std::env::temp_dir;
-    use std::fs;
 
     #[test]
     fn test_derive_seed() {
@@ -347,23 +269,4 @@ pub mod tests {
         assert!(Cli::derive_seed(true, Some(5)).is_err());
         assert!(Cli::derive_seed(true, None).is_ok());
     }
-
-    #[test]
-    fn test_init() {
-        let mut temp_dir = temp_dir();
-        temp_dir.push("synth_test_init");
-
-        // Some environments have temp dir related env vars set, making it sticky (i.e., $TMPDIR).
-        // Remove the contents from previous runs, if needed.
-        if temp_dir.exists() {
-            fs::remove_dir_all(&temp_dir).unwrap();
-            fs::create_dir(&temp_dir).unwrap();
-        }
-
-        let args = Args::Init {
-            init_path: Some(temp_dir.clone()),
-        };
-        let cli = Cli::new(args).unwrap();
-        assert!(cli.init(Some(temp_dir)).is_ok())
-    }
 }


Test patch:
diff --git a/.github/workflows/scripts/test_examples.sh b/.github/workflows/scripts/test_examples.sh
index 6beace34..b28b149f 100644
--- a/.github/workflows/scripts/test_examples.sh
+++ b/.github/workflows/scripts/test_examples.sh
@@ -3,17 +3,12 @@
 cd $1
 for d in */ ; do
     cd "$d"
-    if synth init; then
-        for ns in */ ; do
-            if synth generate $ns --size 10; then
-                echo "Generated $ns"
-            else
-                echo "Failed generating $ns"
-                exit 1
-            fi
-        done
-    else
-        echo "Failed to init $d"
-        exit 1
-    fi
+    for ns in */ ; do
+        if synth generate $ns --size 10; then
+            echo "Generated $ns"
+        else
+            echo "Failed generating $ns"
+            exit 1
+        fi
+    done
 done
\ No newline at end of file